diff --git a/.circleci/config.yml b/.circleci/config.yml index 78520332dfc7e..0ce68b36d9013 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -153,6 +153,7 @@ jobs: `#--enable-werror` - run: name: make + no_output_timeout: 30m command: make -j2 > /dev/null - run: name: make install diff --git a/.gitattributes b/.gitattributes index 86797917210fa..c4e1bd57b2a4b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -21,7 +21,7 @@ # Collapse generated files within git and pull request diff. **/*_arginfo.h linguist-generated -diff -/main/gdb_inlined_script.c linguist-generated -diff +/main/debug_gdb_scripts.c linguist-generated -diff /Zend/zend_vm_execute.h linguist-generated -diff /Zend/zend_vm_handlers.h linguist-generated -diff /Zend/zend_vm_opcodes.[ch] linguist-generated -diff diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5603700ecc98d..9f9d182031d04 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -44,6 +44,7 @@ /ext/pdo_sqlite @SakiTakamachi /ext/pgsql @devnexen /ext/random @TimWolla @zeriyoshi +/ext/reflection @DanielEScherzer /ext/session @Girgias /ext/simplexml @nielsdos /ext/soap @nielsdos diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index acd9c1220c20e..f0f80bd98e324 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -22,15 +22,22 @@ body: ``` validations: required: true - - type: input + - type: textarea attributes: label: PHP Version - description: "The used PHP version. Make sure it is [supported](https://www.php.net/supported-versions.php)." - placeholder: "PHP 8.0.12" + description: | + Please run PHP with the `-v` flag (e.g. `php -v`, `php8.3 -v`, `php-fpm -v` or similar) and provide the full output of that command. If executing that command is not possible, please provide the full version number as given in PHPInfo. + + Please make sure that the used PHP version [is a supported version](https://www.php.net/supported-versions.php). + placeholder: | + PHP 8.3.19 (cli) (built: Mar 13 2025 17:44:40) (NTS) + Copyright (c) The PHP Group + Zend Engine v4.3.19, Copyright (c) Zend Technologies + with Zend OPcache v8.3.19, Copyright (c), by Zend Technologies validations: required: true - type: input attributes: label: Operating System description: "The used operating system, if relevant." - placeholder: "Ubuntu 20.04" + placeholder: "Ubuntu 24.04" diff --git a/.github/scripts/windows/test_task.bat b/.github/scripts/windows/test_task.bat index e15259b3acc39..43e7763e70294 100644 --- a/.github/scripts/windows/test_task.bat +++ b/.github/scripts/windows/test_task.bat @@ -58,12 +58,15 @@ if "%PLATFORM%" == "x64" ( curl -sLo Firebird.zip %PHP_FIREBIRD_DOWNLOAD_URL% 7z x -oC:\Firebird Firebird.zip set PDO_FIREBIRD_TEST_DATABASE=C:\test.fdb -set PDO_FIREBIRD_TEST_DSN=firebird:dbname=%PDO_FIREBIRD_TEST_DATABASE% +set PDO_FIREBIRD_TEST_DSN=firebird:dbname=127.0.0.1:%PDO_FIREBIRD_TEST_DATABASE% set PDO_FIREBIRD_TEST_USER=SYSDBA set PDO_FIREBIRD_TEST_PASS=phpfi +echo create user %PDO_FIREBIRD_TEST_USER% password '%PDO_FIREBIRD_TEST_PASS%';> C:\Firebird\create_user.sql +echo commit;>> C:\Firebird\create_user.sql echo create database '%PDO_FIREBIRD_TEST_DATABASE%' user '%PDO_FIREBIRD_TEST_USER%' password '%PDO_FIREBIRD_TEST_PASS%';> C:\Firebird\setup.sql C:\Firebird\instsvc.exe install -n TestInstance C:\Firebird\isql -q -i C:\Firebird\setup.sql +C:\Firebird\isql -q -i C:\Firebird\create_user.sql -user sysdba %PDO_FIREBIRD_TEST_DATABASE% C:\Firebird\instsvc.exe start -n TestInstance if %errorlevel% neq 0 exit /b 3 path C:\Firebird;%PATH% diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 7993c1b6e3586..c9e6850604312 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -76,11 +76,6 @@ jobs: with: runTestsParameters: >- --asan -x - - name: Notify Slack - if: failure() - uses: ./.github/actions/notify-slack - with: - token: ${{ secrets.ACTION_MONITORING_SLACK }} ALPINE: if: inputs.run_alpine name: ALPINE_X64_ASAN_UBSAN_DEBUG_ZTS diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index b92a55b58b87d..2f82179b90ec6 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -368,6 +368,7 @@ jobs: path: ${{ github.workspace }}/benchmark/profiles retention-days: 30 FREEBSD: + if: github.repository == 'php/php-src' || github.event_name == 'pull_request' name: FREEBSD runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index d8cb25a1a109c..55c441323cf15 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,9 @@ # Libtool library files generated during build process *.la +# Mac shared library files generated during build process +*.dylib + # Directories created by Libtool for storing generated library files .libs/ @@ -234,6 +237,7 @@ php **/tests/**/*.exp **/tests/**/*.log **/tests/**/*.sh +**/tests/**/*.stdin # Generated by some test cases **/tests/**/*.db diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a9f34c239c55e..e5b2e91d63d1b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -353,7 +353,7 @@ Currently, we have the following branches in use: | master | Active development branch for PHP 8.5, which is open for backwards incompatible changes and major internal API changes. | | PHP-8.4 | Is used to release the PHP 8.4.x series. This is a current stable version and is open for bugfixes only. | | PHP-8.3 | Is used to release the PHP 8.3.x series. This is a current stable version and is open for bugfixes only. | -| PHP-8.2 | Is used to release the PHP 8.2.x series. This is a current stable version and is open for bugfixes only. | +| PHP-8.2 | Is used to release the PHP 8.2.x series. This is an old stable version and is open for security fixes only. | | PHP-8.1 | Is used to release the PHP 8.1.x series. This is an old stable version and is open for security fixes only. | | PHP-8.0 | This branch is closed. | | PHP-7.4 | This branch is closed. | diff --git a/EXTENSIONS b/EXTENSIONS index 6c3a83b8d9124..dff81142273d2 100644 --- a/EXTENSIONS +++ b/EXTENSIONS @@ -412,7 +412,7 @@ STATUS: Working ------------------------------------------------------------------------------- EXTENSION: random PRIMARY MAINTAINER Go Kudo (2022 - 2024) - Tim Düsterhus (2022 - 2024) + Tim Düsterhus (2022 - 2025) MAINTENANCE: Maintained STATUS: Working SINCE: 8.2.0 @@ -426,6 +426,7 @@ EXTENSION: reflection PRIMARY MAINTAINER: Marcus Börger (2003 - 2009) Johannes Schlüter (2006 - 2014) Nikita Popov (2019 - 2020) + Daniel Scherzer (2025 - 2025) MAINTENANCE: Maintained STATUS: Working ------------------------------------------------------------------------------- diff --git a/NEWS b/NEWS index cf57d0a36b676..47bf820d6b64c 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,12 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.5.0alpha1 +- BCMath: + . Simplify `bc_divide()` code. (SakiTakamachi) + . If the result is 0, n_scale is set to 0. (SakiTakamachi) + . If size of BC_VECTOR array is within 64 bytes, stack area is now used. + (SakiTakamachi) + - CLI: . Add --ini=diff to print INI settings changed from the builtin default. (timwolla) @@ -27,6 +33,18 @@ PHP NEWS . Fixed bug GH-17442 (Engine UAF with reference assign and dtor). (nielsdos) . Improved error message of UnhandledMatchError for zend.exception_string_param_max_len=0. (timwolla) + . Fixed bug GH-17959 (Relax missing trait fatal error to error exception). + (ilutov) + . Fixed bug GH-18033 (NULL-ptr dereference when using register_tick_function + in destructor). (nielsdos) + . Fixed bug GH-18026 (Improve "expecting token" error for ampersand). (ilutov) + . Added the #[\NoDiscard] attribute to indicate that a function's return + value is important and should be consumed. (timwolla, Volker Dusch) + . Added the (void) cast to indicate that not using a value is intentional. + (timwolla, Volker Dusch) + . Added get_error_handler(), get_exception_handler() functions. (Arnaud) + . Fixed bug GH-15753 and GH-16198 (Bind traits before parent class). (ilutov) + . Added support for casts in constant expressions. (nielsdos) - Curl: . Added curl_multi_get_handles(). (timwolla) @@ -46,9 +64,16 @@ PHP NEWS . Added enchant_dict_remove_from_session(). (nielsdos) . Added enchant_dict_remove(). (nielsdos) +- EXIF: + . Add OffsetTime* Exif tags. (acc987) + - Fileinfo: . Upgrade to file 5.46. (nielsdos) +- FPM: + . Fixed GH-17645 (FPM with httpd ProxyPass does not decode script path). + (Jakub Zelenka) + - GD: . Fixed bug #68629 (Transparent artifacts when using imagerotate). (pierre, cmb) @@ -58,6 +83,10 @@ PHP NEWS . Bumped ICU requirement to ICU >= 57.1. (cmb) . IntlDateFormatter::setTimeZone()/datefmt_set_timezone() throws an exception with uninitialised classes or clone failure. (David Carlier) + . Added DECIMAL_COMPACT_SHORT/DECIMAL_COMPACT_LONG for NumberFormatter class. + (BogdanUngureanu) + . Added Locale::isRightToLeft to check if a locale is written right to left. + (David Carlier) - MySQLi: . Fixed bugs GH-17900 and GH-8084 (calling mysqli::__construct twice). @@ -76,6 +105,8 @@ PHP NEWS - PCRE: . Upgraded to pre2lib from 10.44 to 10.45. (nielsdos) + . Remove PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK from pcre compile options. + (mvorisek) - PDO_PGSQL: . Added Iterable support for PDO::pgsqlCopyFromArray. (KentarouTakeda) @@ -83,6 +114,10 @@ PHP NEWS Pdo\Pgsql::prepare(…, [ PDO::ATTR_PREFETCH => 0 ]) make fetch() lazy instead of storing the whole result set in memory (Guillaume Outters) +- PDO_SQLITE: + . throw on null bytes / resolve GH-13952 (divinity76). + . Implement GH-17321: Add setAuthorizer to Pdo\Sqlite. (nielsdos) + - PGSQL: . Added pg_close_stmt to close a prepared statement while allowing its name to be reused. (David Carlier) @@ -90,6 +125,8 @@ PHP NEWS . pg_connect checks if connection_string contains any null byte, pg_close_stmt check if the statement contains any null byte. (David Carlier) + . Added pg_service to get the connection current service identifier. + (David Carlier) - POSIX: . Added POSIX_SC_OPEN_MAX constant to get the number of file descriptors @@ -106,12 +143,18 @@ PHP NEWS (DanielEScherzer) . Fixed bug GH-12856 (ReflectionClass::getStaticPropertyValue() returns UNDEF zval for uninitialized typed properties). (nielsdos) + . Fixed bug GH-15766 (ReflectionClass::toString() should have better output + for enums). (DanielEScherzer) - Session: . session_start() throws a ValueError on option argument if not a hashmap or a TypeError if read_and_close value is not compatible with int. (David Carlier) +- SimpleXML: + . Fixed bug GH-12231 (SimpleXML xpath should warn when returning other return + types than node lists). (nielsdos) + - SNMP: . snmpget, snmpset, snmp_get2, snmp_set2, snmp_get3, snmp_set3 and SNMP::__construct() throw an exception on invalid hostname, community @@ -148,6 +191,7 @@ PHP NEWS . socket_getsockname/socket_create/socket_bind handled AF_PACKET family socket. (David Carlier) . Added IP_BINDANY for a socket to bind to any address. (David Carlier) + . Added SO_BUSY_POOL to reduce packets poll latency. (David Carlier) - Sodium: . Fix overall theorical overflows on zend_string buffer allocations. @@ -156,6 +200,8 @@ PHP NEWS - Standard: . Fixed crypt() tests on musl when using --with-external-libcrypt (Michael Orlitzky). + . Fixed bug GH-18062 (is_callable(func(...), callable_name: $name) for first + class callables returns wrong name). (timwolla) - Streams: . Fixed bug GH-16889 (stream_select() timeout useless for pipes on Windows). diff --git a/UPGRADING b/UPGRADING index 4129c7349444a..6b6c555adcf73 100644 --- a/UPGRADING +++ b/UPGRADING @@ -38,6 +38,18 @@ PHP 8.5 UPGRADE NOTES resources that were indirectly collected through cycles. . It is now allowed to substitute static with self or the concrete class name in final subclasses. + . The tick handlers are now deactivated after all shutdown functions, destructors + have run and the output handlers have been cleaned up. + This is a consequence of fixing GH-18033. + . Traits are now bound before the parent class. This is a subtle behavioral + change, but should closer match user expectations, demonstrated by GH-15753 + and GH-16198. + +- FileInfo: + . finfo_file() and finfo::file() now throws a ValueError instead of a + TypeError when $filename contains nul bytes. + This aligns the type of Error thrown to be consistent with the rest of + the language. - Intl: . The extension now requires at least ICU 57.1. @@ -56,6 +68,11 @@ PHP 8.5 UPGRADE NOTES . pcntl_exec() now throws ValueErrors when entries or keys of the $env_vars parameter contain null bytes. +- PCRE: + . The extension is compiled without semi-deprecated + PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK compile option. + https://github.com/PCRE2Project/pcre2/issues/736#issuecomment-2754024651 + - PDO: . The constructor arguments set in conjunction with PDO::FETCH_CLASS now follow the usual CUFA (call_user_func_array) semantics. @@ -79,6 +96,11 @@ PHP 8.5 UPGRADE NOTES . A ValueError is now thrown when trying to set a cursor name that is too long on a PDOStatement resulting from the Firebird driver. +- SimpleXML: + - Passing an XPath expression that returns something other than a node set + to SimpleXMLElement::xpath() will now emit a warning and return false, + instead of silently failing and returning an empty array. + - SPL: . ArrayObject no longer accepts enums, as modifying the $name or $value properties can break engine assumptions. @@ -98,6 +120,17 @@ PHP 8.5 UPGRADE NOTES . Fatal Errors (such as an exceeded maximum execution time) now include a backtrace. RFC: https://wiki.php.net/rfc/error_backtraces_v2 + . Added the #[\NoDiscard] attribute to indicate that a function's return + value is important and should be consumed. + RFC: https://wiki.php.net/rfc/marking_return_value_as_important + . Added the (void) cast to indicate that not using a value is intentional. + The (void) cast has no effect on the program's execution by itself, but + it can be used to suppress warnings emitted by #[\NoDiscard] and possibly + also diagnostics emitted by external IDEs or static analysis tools. + RFC: https://wiki.php.net/rfc/marking_return_value_as_important + . Added asymmetric visibility support for static properties. + RFC: https://wiki.php.net/rfc/static-aviz + . Added support for casts in constant expressions. - Curl: . Added support for share handles that are persisted across multiple PHP @@ -115,10 +148,24 @@ PHP 8.5 UPGRADE NOTES indicating the http and proxy authentication methods that were used in the previous request. See CURLAUTH_* constants for possible values. + . Added CURLOPT_INFILESIZE_LARGE Curl option, which is a safe + replacement for CURLOPT_INFILESIZE. On certain systems, + CURLOPT_INFILESIZE only accepts a 32-bit signed integer as the file + size (2.0 GiB) even on 64-bit systems. CURLOPT_INFILESIZE_LARGE + accepts the largest integer value the system can handle. - DOM: . Added Dom\Element::$outerHTML. +- EXIF: + . Add OffsetTime* Exif tags. + +- Intl: + . Added class constants NumberFormatter::CURRENCY_ISO, + NumberFormatter::CURRENCY_PLURAL, NumberFormatter::CASH_CURRENCY, + and NumberFormatter::CURRENCY_STANDARD for various currency-related + number formats. + - XSL: . The $namespace argument of XSLTProcessor::getParameter(), XSLTProcessor::setParameter() and XSLTProcessor::removeParameter() @@ -141,6 +188,10 @@ PHP 8.5 UPGRADE NOTES . Added a new --ini=diff option to print INI settings changed from the builtin default. +- FPM: + . FPM with httpd ProxyPass decodes the full script path. Added + fastcgi.script_path_encoded INI setting to prevent this new behavior. + ======================================== 4. Deprecated Functionality ======================================== @@ -171,6 +222,10 @@ PHP 8.5 UPGRADE NOTES PDO::ATTR_PREFETCH sets to 0 which set to lazy fetch mode. In this mode, statements cannot be run parallely. +- PDO_SQLITE: + . SQLite PDO::quote() will now throw an exception or emit a warning, + depending on the error mode, if the string contains a null byte. + - PGSQL: . pg_copy_from also supports inputs as Iterable. . pg_connect checks if the connection_string argument contains @@ -186,6 +241,11 @@ PHP 8.5 UPGRADE NOTES . posix_fpathconf checks invalid file descriptors and sets last_error to EBADF and raises an E_WARNING message. +- Reflection: + . The output of ReflectionClass::toString() for enums has changed to + better indicate that the class is an enum, and that the enum cases + are enum cases rather than normal class constants. + - Session: . session_start is stricter in regard of the option argument. It throws a ValueError if the whole is not a hashmap or @@ -224,6 +284,14 @@ PHP 8.5 UPGRADE NOTES 6. New Functions ======================================== +- Core: + . get_error_handler() allows retrieving the current user-defined error handler + function. + RFC: https://wiki.php.net/rfc/get-error-exception-handler + . get_exception_handler() allows retrieving the current user-defined exception + handler function. + RFC: https://wiki.php.net/rfc/get-error-exception-handler + - Curl: . curl_multi_get_handles() allows retrieving all CurlHandles current attached to a CurlMultiHandle. This includes both handles added using @@ -241,10 +309,20 @@ PHP 8.5 UPGRADE NOTES . Added enchant_dict_remove() to put a word on the exclusion list and remove it from the session dictionary. +- Intl: + . Added locale_is_right_to_left/Locale::isRightToLeft, returns true if + the locale is written right to left (after its enrichment with likely subtags). + +- Pdo\Sqlite: + . Added support for Pdo\Sqlite::setAuthorizer(), which is the equivalent of + SQLite3::setAuthorizer(). The only interface difference is that the + pdo version returns void. + - PGSQL: . pg_close_stmt offers an alternative way to close a prepared statement from the DEALLOCATE sql command in that we can reuse its name afterwards. + . pg_service returns the ongoing service name of the connection. - Reflection: . ReflectionConstant::getFileName() was introduced. @@ -290,6 +368,11 @@ PHP 8.5 UPGRADE NOTES . CURLINFO_USED_PROXY. . CURLINFO_HTTPAUTH_USED. . CURLINFO_PROXYAUTH_USED. + . CURLOPT_INFILESIZE_LARGE. + +- Intl: + . DECIMAL_COMPACT_SHORT. + . DECIMAL_COMPACT_LONG. - POSIX: . POSIX_SC_OPEN_MAX. @@ -304,6 +387,7 @@ PHP 8.5 UPGRADE NOTES . TCP_BBR_ALGORITHM (FreeBSD only). . AF_PACKET (Linux only). . IP_BINDANY (FreeBSD/NetBSD/OpenBSD only). + . SO_BUSY_POLL (Linux only). ======================================== 11. Changes to INI File Handling @@ -381,6 +465,13 @@ PHP 8.5 UPGRADE NOTES . Improved performance of the following methods: getValue(), getRawValue(), isInitialized(), setValue(), setRawValue(). +- SPL: + . Improved performance of dimension accessors and methods of SplFixedArray. + +- Standard: + . Improved performance of array functions with callbacks + (array_find, array_filter, array_map, usort, ...). + - XMLReader: . Improved property access performance. diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index b963ead5cc8da..56c7535158460 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -19,6 +19,14 @@ PHP 8.5 INTERNALS UPGRADE NOTES a value to a non-reference zval. . Added zval_ptr_safe_dtor() to safely destroy a zval when a destructor could interfere. + . zend_get_callable_name() now returns the name of the underlying function + for fake closures. + . Added smart_string_append_printf() matching smart_str_append_printf() for + char* instead of zend_string*-based smart strings. + . Added php_build_provider() to retrieve the value of PHP_BUILD_PROVIDER at + runtime. + . Removed the cache_slot argument of zend_check_user_type_slow() because + now it only relies on the CE cache. ======================== 2. Build system changes diff --git a/Zend/Optimizer/block_pass.c b/Zend/Optimizer/block_pass.c index 6fcbd04f12af5..2b6d71c385457 100644 --- a/Zend/Optimizer/block_pass.c +++ b/Zend/Optimizer/block_pass.c @@ -274,7 +274,9 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array * If it's not local, then the other blocks successors must also eventually either FREE or consume the temporary, * hence removing the temporary is not safe in the general case, especially when other consumers are not FREE. * A FREE may not be removed without also removing the source's result, because otherwise that would cause a memory leak. */ - if (opline->op1_type == IS_TMP_VAR) { + if (opline->extended_value == ZEND_FREE_VOID_CAST) { + /* Keep the ZEND_FREE opcode alive. */ + } else if (opline->op1_type == IS_TMP_VAR) { src = VAR_SOURCE(opline->op1); if (src) { switch (src->opcode) { diff --git a/Zend/Optimizer/compact_literals.c b/Zend/Optimizer/compact_literals.c index 4b27aebc9d39a..d0aaccec7ce2c 100644 --- a/Zend/Optimizer/compact_literals.c +++ b/Zend/Optimizer/compact_literals.c @@ -43,50 +43,6 @@ typedef struct _literal_info { info[n].num_related = (related); \ } while (0) -static size_t type_num_classes(const zend_op_array *op_array, uint32_t arg_num) -{ - zend_arg_info *arg_info; - if (arg_num > 0) { - if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) { - return 0; - } - if (EXPECTED(arg_num <= op_array->num_args)) { - arg_info = &op_array->arg_info[arg_num-1]; - } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) { - arg_info = &op_array->arg_info[op_array->num_args]; - } else { - return 0; - } - } else { - arg_info = op_array->arg_info - 1; - } - - if (ZEND_TYPE_IS_COMPLEX(arg_info->type)) { - if (ZEND_TYPE_HAS_LIST(arg_info->type)) { - /* Intersection types cannot have nested list types */ - if (ZEND_TYPE_IS_INTERSECTION(arg_info->type)) { - return ZEND_TYPE_LIST(arg_info->type)->num_types; - } - ZEND_ASSERT(ZEND_TYPE_IS_UNION(arg_info->type)); - size_t count = 0; - zend_type *list_type; - - ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(arg_info->type), list_type) { - if (ZEND_TYPE_IS_INTERSECTION(*list_type)) { - count += ZEND_TYPE_LIST(*list_type)->num_types; - } else { - ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type)); - count += 1; - } - } ZEND_TYPE_LIST_FOREACH_END(); - return count; - } - return 1; - } - - return 0; -} - static uint32_t add_static_slot(HashTable *hash, zend_op_array *op_array, uint32_t op1, @@ -165,7 +121,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx HashTable hash; zend_string *key = NULL; void *checkpoint = zend_arena_checkpoint(ctx->arena); - int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot; + int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot, *jmp_slot; if (op_array->last_literal) { info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info)); @@ -175,6 +131,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx end = opline + op_array->last; while (opline < end) { switch (opline->opcode) { + case ZEND_JMP_FRAMELESS: + LITERAL_INFO(opline->op1.constant, 1); + break; case ZEND_INIT_FCALL_BY_NAME: LITERAL_INFO(opline->op2.constant, 2); break; @@ -480,13 +439,14 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx zend_hash_clean(&hash); op_array->last_literal = j; - const_slot = zend_arena_alloc(&ctx->arena, j * 6 * sizeof(int)); - memset(const_slot, -1, j * 6 * sizeof(int)); + const_slot = zend_arena_alloc(&ctx->arena, j * 7 * sizeof(int)); + memset(const_slot, -1, j * 7 * sizeof(int)); class_slot = const_slot + j; func_slot = class_slot + j; bind_var_slot = func_slot + j; property_slot = bind_var_slot + j; method_slot = property_slot + j; + jmp_slot = method_slot + j; /* Update opcodes to use new literals table */ cache_size = zend_op_array_extension_handles * sizeof(void*); @@ -500,26 +460,6 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx opline->op2.constant = map[opline->op2.constant]; } switch (opline->opcode) { - case ZEND_RECV_INIT: - case ZEND_RECV: - case ZEND_RECV_VARIADIC: - { - size_t num_classes = type_num_classes(op_array, opline->op1.num); - if (num_classes) { - opline->extended_value = cache_size; - cache_size += num_classes * sizeof(void *); - } - break; - } - case ZEND_VERIFY_RETURN_TYPE: - { - size_t num_classes = type_num_classes(op_array, 0); - if (num_classes) { - opline->op2.num = cache_size; - cache_size += num_classes * sizeof(void *); - } - break; - } case ZEND_ASSIGN_STATIC_PROP_OP: if (opline->op1_type == IS_CONST) { // op1 static property @@ -773,10 +713,19 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx break; case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_CLASS_DELAYED: - case ZEND_JMP_FRAMELESS: opline->extended_value = cache_size; cache_size += sizeof(void *); break; + case ZEND_JMP_FRAMELESS: + // op1 func + if (jmp_slot[opline->op1.constant] >= 0) { + opline->extended_value = jmp_slot[opline->op1.constant]; + } else { + opline->extended_value = cache_size; + cache_size += sizeof(void *); + jmp_slot[opline->op1.constant] = opline->extended_value; + } + break; case ZEND_SEND_VAL: case ZEND_SEND_VAL_EX: case ZEND_SEND_VAR: diff --git a/Zend/Optimizer/dce.c b/Zend/Optimizer/dce.c index 414abe01f96ac..a00fd8bc6ad30 100644 --- a/Zend/Optimizer/dce.c +++ b/Zend/Optimizer/dce.c @@ -80,7 +80,6 @@ static inline bool may_have_side_effects( case ZEND_IS_IDENTICAL: case ZEND_IS_NOT_IDENTICAL: case ZEND_QM_ASSIGN: - case ZEND_FREE: case ZEND_FE_FREE: case ZEND_TYPE_CHECK: case ZEND_DEFINED: @@ -127,6 +126,8 @@ static inline bool may_have_side_effects( case ZEND_ARRAY_KEY_EXISTS: /* No side effects */ return 0; + case ZEND_FREE: + return opline->extended_value == ZEND_FREE_VOID_CAST; case ZEND_ADD_ARRAY_ELEMENT: /* TODO: We can't free two vars. Keep instruction alive. "$b"]; */ if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) { diff --git a/Zend/Optimizer/dfa_pass.c b/Zend/Optimizer/dfa_pass.c index ce2a19f2e8fe9..bf85764c93b49 100644 --- a/Zend/Optimizer/dfa_pass.c +++ b/Zend/Optimizer/dfa_pass.c @@ -254,7 +254,7 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op free_alloca(shiftlist, use_heap); } -static bool safe_instanceof(zend_class_entry *ce1, zend_class_entry *ce2) { +static bool safe_instanceof(const zend_class_entry *ce1, const zend_class_entry *ce2) { if (ce1 == ce2) { return 1; } @@ -267,9 +267,9 @@ static bool safe_instanceof(zend_class_entry *ce1, zend_class_entry *ce2) { static inline bool can_elide_list_type( const zend_script *script, const zend_op_array *op_array, - const zend_ssa_var_info *use_info, zend_type type) + const zend_ssa_var_info *use_info, const zend_type type) { - zend_type *single_type; + const zend_type *single_type; /* For intersection: result==false is failure, default is success. * For union: result==true is success, default is failure. */ bool is_intersection = ZEND_TYPE_IS_INTERSECTION(type); @@ -280,7 +280,7 @@ static inline bool can_elide_list_type( } if (ZEND_TYPE_HAS_NAME(*single_type)) { zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(*single_type)); - zend_class_entry *ce = zend_optimizer_get_class_entry(script, op_array, lcname); + const zend_class_entry *ce = zend_optimizer_get_class_entry(script, op_array, lcname); zend_string_release(lcname); bool result = ce && safe_instanceof(use_info->ce, ce); if (result == !is_intersection) { @@ -407,40 +407,28 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa) zend_call_info *call_info = func_info->callee_info; do { - if (call_info->caller_call_opline - && call_info->caller_call_opline->opcode == ZEND_DO_ICALL + zend_op *op = call_info->caller_init_opline; + + if ((op->opcode == ZEND_FRAMELESS_ICALL_2 + || (op->opcode == ZEND_FRAMELESS_ICALL_3 && (op + 1)->op1_type == IS_CONST)) && call_info->callee_func - && zend_string_equals_literal(call_info->callee_func->common.function_name, "in_array") - && (call_info->caller_init_opline->extended_value == 2 - || (call_info->caller_init_opline->extended_value == 3 - && (call_info->caller_call_opline - 1)->opcode == ZEND_SEND_VAL - && (call_info->caller_call_opline - 1)->op1_type == IS_CONST))) { - - zend_op *send_array; - zend_op *send_needly; + && zend_string_equals_literal_ci(call_info->callee_func->common.function_name, "in_array")) { + bool strict = 0; + bool has_opdata = op->opcode == ZEND_FRAMELESS_ICALL_3; ZEND_ASSERT(!call_info->is_prototype); - if (call_info->caller_init_opline->extended_value == 2) { - send_array = call_info->caller_call_opline - 1; - send_needly = call_info->caller_call_opline - 2; - } else { - if (zend_is_true(CT_CONSTANT_EX(op_array, (call_info->caller_call_opline - 1)->op1.constant))) { + if (has_opdata) { + if (zend_is_true(CT_CONSTANT_EX(op_array, (op + 1)->op1.constant))) { strict = 1; } - send_array = call_info->caller_call_opline - 2; - send_needly = call_info->caller_call_opline - 3; } - if (send_array->opcode == ZEND_SEND_VAL - && send_array->op1_type == IS_CONST - && Z_TYPE_P(CT_CONSTANT_EX(op_array, send_array->op1.constant)) == IS_ARRAY - && (send_needly->opcode == ZEND_SEND_VAL - || send_needly->opcode == ZEND_SEND_VAR) - ) { + if (op->op2_type == IS_CONST + && Z_TYPE_P(CT_CONSTANT_EX(op_array, op->op2.constant)) == IS_ARRAY) { bool ok = 1; - HashTable *src = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, send_array->op1.constant)); + HashTable *src = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, op->op2.constant)); HashTable *dst; zval *val, tmp; zend_ulong idx; @@ -471,59 +459,15 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa) } if (ok) { - uint32_t op_num = send_needly - op_array->opcodes; - zend_ssa_op *ssa_op = ssa->ops + op_num; - - if (ssa_op->op1_use >= 0) { - /* Reconstruct SSA */ - int var_num = ssa_op->op1_use; - zend_ssa_var *var = ssa->vars + var_num; - - ZEND_ASSERT(ssa_op->op1_def < 0); - zend_ssa_unlink_use_chain(ssa, op_num, ssa_op->op1_use); - ssa_op->op1_use = -1; - ssa_op->op1_use_chain = -1; - op_num = call_info->caller_call_opline - op_array->opcodes; - ssa_op = ssa->ops + op_num; - ssa_op->op1_use = var_num; - ssa_op->op1_use_chain = var->use_chain; - var->use_chain = op_num; - } - ZVAL_ARR(&tmp, dst); /* Update opcode */ - call_info->caller_call_opline->opcode = ZEND_IN_ARRAY; - call_info->caller_call_opline->extended_value = strict; - call_info->caller_call_opline->op1_type = send_needly->op1_type; - call_info->caller_call_opline->op1.num = send_needly->op1.num; - call_info->caller_call_opline->op2_type = IS_CONST; - call_info->caller_call_opline->op2.constant = zend_optimizer_add_literal(op_array, &tmp); - if (call_info->caller_init_opline->extended_value == 3) { - MAKE_NOP(call_info->caller_call_opline - 1); - } - MAKE_NOP(call_info->caller_init_opline); - MAKE_NOP(send_needly); - MAKE_NOP(send_array); - removed_ops++; - - op_num = call_info->caller_call_opline - op_array->opcodes; - ssa_op = ssa->ops + op_num; - if (ssa_op->result_def >= 0) { - int var = ssa_op->result_def; - int use = ssa->vars[var].use_chain; - - /* If the result is used only in a JMPZ/JMPNZ, replace result type with - * IS_TMP_VAR, which will enable use of smart branches. Don't do this - * in other cases, as not all opcodes support both VAR and TMP. */ - if (ssa->vars[var].phi_use_chain == NULL - && ssa->ops[use].op1_use == var - && ssa->ops[use].op1_use_chain == -1 - && (op_array->opcodes[use].opcode == ZEND_JMPZ - || op_array->opcodes[use].opcode == ZEND_JMPNZ)) { - call_info->caller_call_opline->result_type = IS_TMP_VAR; - op_array->opcodes[use].op1_type = IS_TMP_VAR; - } + op->opcode = ZEND_IN_ARRAY; + op->extended_value = strict; + op->op2.constant = zend_optimizer_add_literal(op_array, &tmp); + if (has_opdata) { + MAKE_NOP(op + 1); + removed_ops++; } } } diff --git a/Zend/Optimizer/optimize_func_calls.c b/Zend/Optimizer/optimize_func_calls.c index ce6c43afaedbe..8b29f47c94976 100644 --- a/Zend/Optimizer/optimize_func_calls.c +++ b/Zend/Optimizer/optimize_func_calls.c @@ -78,8 +78,10 @@ static void zend_delete_call_instructions(zend_op_array *op_array, zend_op *opli static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_op *opline, zend_function *func) { + const uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD; + if (func->type == ZEND_USER_FUNCTION - && !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_DEPRECATED)) + && !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_DEPRECATED|no_discard)) /* TODO: function copied from trait may be inconsistent ??? */ && !(func->op_array.fn_flags & (ZEND_ACC_TRAIT_CLONE)) && fcall->extended_value >= func->op_array.required_num_args @@ -202,18 +204,12 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); literal_dtor(&ZEND_OP2_LITERAL(fcall)); fcall->op2.constant = fcall->op2.constant + 1; - if (opline->opcode != ZEND_CALLABLE_CONVERT) { - opline->opcode = zend_get_call_op(fcall, call_stack[call].func); - } } else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { fcall->opcode = ZEND_INIT_FCALL; fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); literal_dtor(&op_array->literals[fcall->op2.constant]); literal_dtor(&op_array->literals[fcall->op2.constant + 2]); fcall->op2.constant = fcall->op2.constant + 1; - if (opline->opcode != ZEND_CALLABLE_CONVERT) { - opline->opcode = zend_get_call_op(fcall, call_stack[call].func); - } } else if (fcall->opcode == ZEND_INIT_STATIC_METHOD_CALL || fcall->opcode == ZEND_INIT_METHOD_CALL || fcall->opcode == ZEND_INIT_PARENT_PROPERTY_HOOK_CALL @@ -223,6 +219,16 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) ZEND_UNREACHABLE(); } + /* If the INIT opcode changed the DO opcode can also change to + * a more optimized one. + * + * At this point we also know whether or not the result of + * the DO opcode is used, allowing to optimize calls to + * ZEND_ACC_NODISCARD functions. */ + if (opline->opcode != ZEND_CALLABLE_CONVERT) { + opline->opcode = zend_get_call_op(fcall, call_stack[call].func, !RESULT_UNUSED(opline)); + } + if ((ZEND_OPTIMIZER_PASS_16 & ctx->optimization_level) && call_stack[call].try_inline && opline->opcode != ZEND_CALLABLE_CONVERT) { diff --git a/Zend/Optimizer/zend_cfg.c b/Zend/Optimizer/zend_cfg.c index a05cf6fb79235..a0d08b67aa70c 100644 --- a/Zend/Optimizer/zend_cfg.c +++ b/Zend/Optimizer/zend_cfg.c @@ -143,7 +143,11 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg * end = blocks + block_map[op_array->try_catch_array[j].finally_op]; while (b != end) { if (b->flags & ZEND_BB_REACHABLE) { - op_array->try_catch_array[j].try_op = op_array->try_catch_array[j].catch_op; + /* In case we get here, there is no live try block but there is a live finally block. + * If we do have catch_op set, we need to set it to the first catch block to satisfy + * the constraint try_op <= catch_op <= finally_op */ + op_array->try_catch_array[j].try_op = + op_array->try_catch_array[j].catch_op ? op_array->try_catch_array[j].catch_op : b->start; changed = 1; zend_mark_reachable(op_array->opcodes, cfg, blocks + block_map[op_array->try_catch_array[j].try_op]); break; diff --git a/Zend/asm/save_xmm_x86_64_ms_masm.asm b/Zend/asm/save_xmm_x86_64_ms_masm.asm new file mode 100644 index 0000000000000..1569d6bdb0e86 --- /dev/null +++ b/Zend/asm/save_xmm_x86_64_ms_masm.asm @@ -0,0 +1,43 @@ +.code + +; ZEND_API void execute_ex(zend_execute_data *ex) +PUBLIC execute_ex + +EXTERN execute_ex_real:PROC + +; Assembly wrapper around the real execute_ex function, so that we can +; save the preserved registers when re-entering the VM from JIT code. +; See GH-18136. +execute_ex PROC EXPORT FRAME + ; 10 floating points numbers + ; 32 bytes shadow space + ; 8 bytes to align after the return address + sub rsp, 8*10 + 32 + 8 + .allocstack 8*10 + 32 + 8 + .endprolog + movsd qword ptr [rsp + 32 + 8*0], xmm6 + movsd qword ptr [rsp + 32 + 8*1], xmm7 + movsd qword ptr [rsp + 32 + 8*2], xmm8 + movsd qword ptr [rsp + 32 + 8*3], xmm9 + movsd qword ptr [rsp + 32 + 8*4], xmm10 + movsd qword ptr [rsp + 32 + 8*5], xmm11 + movsd qword ptr [rsp + 32 + 8*6], xmm12 + movsd qword ptr [rsp + 32 + 8*7], xmm13 + movsd qword ptr [rsp + 32 + 8*8], xmm14 + movsd qword ptr [rsp + 32 + 8*9], xmm15 + call execute_ex_real + movsd xmm6, qword ptr [rsp + 32 + 8*0] + movsd xmm7, qword ptr [rsp + 32 + 8*1] + movsd xmm8, qword ptr [rsp + 32 + 8*2] + movsd xmm9, qword ptr [rsp + 32 + 8*3] + movsd xmm10, qword ptr [rsp + 32 + 8*4] + movsd xmm11, qword ptr [rsp + 32 + 8*5] + movsd xmm12, qword ptr [rsp + 32 + 8*6] + movsd xmm13, qword ptr [rsp + 32 + 8*7] + movsd xmm14, qword ptr [rsp + 32 + 8*8] + movsd xmm15, qword ptr [rsp + 32 + 8*9] + add rsp, 8*10 + 32 + 8 + ret +execute_ex ENDP + +END diff --git a/Zend/tests/access_modifiers/access_modifiers_002.phpt b/Zend/tests/access_modifiers/access_modifiers_002.phpt index 9830258c619b4..835d7445aac08 100644 --- a/Zend/tests/access_modifiers/access_modifiers_002.phpt +++ b/Zend/tests/access_modifiers/access_modifiers_002.phpt @@ -1,5 +1,5 @@ --TEST-- -using multiple access modifiers (attributes) +using multiple access modifiers (properties) --FILE-- getMessage(), "\n"; + } + var_dump(C::$prop); + + C::setProp(3); + var_dump(C::$prop); + + try { + ++C::$prop; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop); + + try { + C::$prop++; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop); + + try { + C::$prop += str_repeat('a', 10); + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop); + + try { + $ref = &C::$prop; + $ref++; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop); + + try { + $ref = 4; + C::$prop = &$ref; + $ref++; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop); + + try { + C::$prop2[] = 'foo'; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop2); + + C::addProp2('bar'); + var_dump(C::$prop2); + + C::$prop3->foo = 'foo'; + var_dump(C::$prop3); + + unset(C::$unset->foo); } +test(); +echo "\nRepeat:\n"; +test(); + ?> --EXPECTF-- -Fatal error: Static property may not have asymmetric visibility in %s on line %d +Cannot modify private(set) property C::$prop from global scope +int(1) +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop2 from global scope +array(0) { +} +array(1) { + [0]=> + string(3) "bar" +} +object(stdClass)#%d (1) { + ["foo"]=> + string(3) "foo" +} + +Repeat: +Cannot modify private(set) property C::$prop from global scope +int(1) +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop2 from global scope +array(0) { +} +array(1) { + [0]=> + string(3) "bar" +} +object(stdClass)#%d (1) { + ["foo"]=> + string(3) "foo" +} diff --git a/Zend/tests/attributes/deprecated/class_constants/gh17711.phpt b/Zend/tests/attributes/deprecated/class_constants/gh17711.phpt new file mode 100644 index 0000000000000..abec209343ab3 --- /dev/null +++ b/Zend/tests/attributes/deprecated/class_constants/gh17711.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-17711: Infinite recursion through deprecated class constants self-referencing through deprecation message +--FILE-- + +--EXPECTF-- +Deprecated: Constant C::C is deprecated, Message in %s on line %d +string(7) "Message" + +Deprecated: Constant D::C is deprecated, test in %s on line %d +string(4) "test" diff --git a/Zend/tests/attributes/nodiscard/001.phpt b/Zend/tests/attributes/nodiscard/001.phpt new file mode 100644 index 0000000000000..8bec9972aed67 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/001.phpt @@ -0,0 +1,86 @@ +--TEST-- +#[\NoDiscard]: Basic test. +--FILE-- +test(); +$cls->test2(); +Clazz::test3(); + +call_user_func([$cls, "test"]); + +$closure(); + +$closure2(); + +?> +--EXPECTF-- +Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function test2() should either be used or intentionally ignored by casting it as (void), this is important in %s on line %d + +Warning: The return value of function test3() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of method Clazz::test() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of method Clazz::test2() should either be used or intentionally ignored by casting it as (void), this is important in %s on line %d + +Warning: The return value of method Clazz::test3() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of method Clazz::test() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function {closure:%s:%d}() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function {closure:%s:%d}() should either be used or intentionally ignored by casting it as (void) in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/002.phpt b/Zend/tests/attributes/nodiscard/002.phpt new file mode 100644 index 0000000000000..618aa2f6286d6 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/002.phpt @@ -0,0 +1,44 @@ +--TEST-- +#[\NoDiscard]: __call(), __callStatic(), and __invoke(). +--FILE-- +test(); +Clazz::test(); +$cls('foo'); + +?> +--EXPECTF-- +Warning: The return value of method Clazz::test() should either be used or intentionally ignored by casting it as (void) in %s on line %d +__call(test) + +Warning: The return value of method Clazz::test() should either be used or intentionally ignored by casting it as (void) in %s on line %d +__callStatic(test) + +Warning: The return value of method Clazz::__invoke() should either be used or intentionally ignored by casting it as (void) in %s on line %d +__invoke(foo) + diff --git a/Zend/tests/attributes/nodiscard/003.phpt b/Zend/tests/attributes/nodiscard/003.phpt new file mode 100644 index 0000000000000..24865f350472c --- /dev/null +++ b/Zend/tests/attributes/nodiscard/003.phpt @@ -0,0 +1,22 @@ +--TEST-- +#[\NoDiscard]: Taken from trait. +--FILE-- +test(); + +?> +--EXPECTF-- +Warning: The return value of method Clazz::test() should either be used or intentionally ignored by casting it as (void) in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/005.phpt b/Zend/tests/attributes/nodiscard/005.phpt new file mode 100644 index 0000000000000..9ef1566372892 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/005.phpt @@ -0,0 +1,11 @@ +--TEST-- +#[\NoDiscard]: Native method. +--FILE-- +setTimestamp(0); + +?> +--EXPECTF-- +Warning: The return value of method DateTimeImmutable::setTimestamp() should either be used or intentionally ignored by casting it as (void), as DateTimeImmutable::setTimestamp() does not modify the object itself in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/006.phpt b/Zend/tests/attributes/nodiscard/006.phpt new file mode 100644 index 0000000000000..959b942522204 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/006.phpt @@ -0,0 +1,20 @@ +--TEST-- +#[\NoDiscard]: execute_ex overwritten +--EXTENSIONS-- +zend_test +--INI-- +zend_test.replace_zend_execute_ex=1 +opcache.jit=disable +--FILE-- + +--EXPECTF-- +Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/007.phpt b/Zend/tests/attributes/nodiscard/007.phpt new file mode 100644 index 0000000000000..1b72de8c22a06 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/007.phpt @@ -0,0 +1,17 @@ +--TEST-- +#[\NoDiscard]: execute_internal overwritten +--EXTENSIONS-- +zend_test +--INI-- +zend_test.observer.execute_internal=1 +--FILE-- + +--EXPECTF-- + + +Warning: The return value of function zend_test_nodiscard() should either be used or intentionally ignored by casting it as (void), custom message in %s on line %d + diff --git a/Zend/tests/attributes/nodiscard/008.phpt b/Zend/tests/attributes/nodiscard/008.phpt new file mode 100644 index 0000000000000..6b4635e08d562 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/008.phpt @@ -0,0 +1,18 @@ +--TEST-- +#[\NoDiscard]: Combining with #[\Deprecated]. +--FILE-- + +--EXPECTF-- +Deprecated: Function test() is deprecated in %s on line %d + +Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/009.phpt b/Zend/tests/attributes/nodiscard/009.phpt new file mode 100644 index 0000000000000..ab887db7a14b0 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/009.phpt @@ -0,0 +1,14 @@ +--TEST-- +#[\NoDiscard]: Combining with #[\Deprecated] (Internal). +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECTF-- +Deprecated: Function zend_test_deprecated_nodiscard() is deprecated, custom message in %s on line %d + +Warning: The return value of function zend_test_deprecated_nodiscard() should either be used or intentionally ignored by casting it as (void), custom message 2 in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/010.phpt b/Zend/tests/attributes/nodiscard/010.phpt new file mode 100644 index 0000000000000..5534fc3404da9 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/010.phpt @@ -0,0 +1,12 @@ +--TEST-- +#[\NoDiscard]: Native function. +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECTF-- +Warning: The return value of function zend_test_nodiscard() should either be used or intentionally ignored by casting it as (void), custom message in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/error_code_001.phpt b/Zend/tests/attributes/nodiscard/error_code_001.phpt new file mode 100644 index 0000000000000..2952587db7b87 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/error_code_001.phpt @@ -0,0 +1,21 @@ +--TEST-- +#[\NoDiscard]: Code is E_USER_WARNING. +--FILE-- + +--EXPECT-- +int(512) +int(512) +bool(true) diff --git a/Zend/tests/attributes/nodiscard/property_readonly_001.phpt b/Zend/tests/attributes/nodiscard/property_readonly_001.phpt new file mode 100644 index 0000000000000..6f9779023126e --- /dev/null +++ b/Zend/tests/attributes/nodiscard/property_readonly_001.phpt @@ -0,0 +1,14 @@ +--TEST-- +#[\NoDiscard]: NoDiscard::$message is readonly. +--FILE-- +message = 'bar'; + +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot modify readonly property NoDiscard::$message in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/property_readonly_002.phpt b/Zend/tests/attributes/nodiscard/property_readonly_002.phpt new file mode 100644 index 0000000000000..f01594ca4b26c --- /dev/null +++ b/Zend/tests/attributes/nodiscard/property_readonly_002.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\NoDiscard]: __construct() respects that properties are readonly. +--FILE-- +__construct("bar"); + +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot modify readonly property NoDiscard::$message in %s:%d +Stack trace: +#0 %s(%d): NoDiscard->__construct('bar') +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/suppress_assign.phpt b/Zend/tests/attributes/nodiscard/suppress_assign.phpt new file mode 100644 index 0000000000000..b09f1a39718a8 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/suppress_assign.phpt @@ -0,0 +1,66 @@ +--TEST-- +#[\NoDiscard]: Assigning to variable suppresses. +--FILE-- +test(); +$_ = $cls->test2(); +$_ = call_user_func([$cls, "test"]); +$_ = Clazz::test3(); + +$_ = $closure(); + +$_ = $closure2(); + +?> +DONE +--EXPECT-- +DONE diff --git a/Zend/tests/attributes/nodiscard/suppress_cast.phpt b/Zend/tests/attributes/nodiscard/suppress_cast.phpt new file mode 100644 index 0000000000000..2f639371cb3dd --- /dev/null +++ b/Zend/tests/attributes/nodiscard/suppress_cast.phpt @@ -0,0 +1,66 @@ +--TEST-- +#[\NoDiscard]: Casting to (void) suppresses. +--FILE-- +test(); +(void)$cls->test2(); +(void)call_user_func([$cls, "test"]); +(void)Clazz::test3(); + +(void)$closure(); + +(void)$closure2(); + +?> +DONE +--EXPECT-- +DONE diff --git a/Zend/tests/attributes/nodiscard/throwing_error_handler_001.phpt b/Zend/tests/attributes/nodiscard/throwing_error_handler_001.phpt new file mode 100644 index 0000000000000..51179b26ab194 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/throwing_error_handler_001.phpt @@ -0,0 +1,35 @@ +--TEST-- +#[\NoDiscard]: Throwing error handler. +--FILE-- +getMessage(), PHP_EOL; +} + +#[\NoDiscard] +function test2(): stdClass { + return new stdClass(); +} + +try { + test2(); +} catch (ErrorException $e) { + echo "Caught: ", $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Caught: The return value of function test() should either be used or intentionally ignored by casting it as (void) +Caught: The return value of function test2() should either be used or intentionally ignored by casting it as (void) diff --git a/Zend/tests/attributes/nodiscard/type_validation_001.phpt b/Zend/tests/attributes/nodiscard/type_validation_001.phpt new file mode 100644 index 0000000000000..b7a375ada5c07 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/type_validation_001.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\NoDiscard]: Type validation of $message parameter with int. +--FILE-- + +--EXPECTF-- +Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void), 1234 in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/type_validation_002.phpt b/Zend/tests/attributes/nodiscard/type_validation_002.phpt new file mode 100644 index 0000000000000..254fae15ac47a --- /dev/null +++ b/Zend/tests/attributes/nodiscard/type_validation_002.phpt @@ -0,0 +1,20 @@ +--TEST-- +#[\NoDiscard]: Type validation of $message parameter with int and strict types. +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught TypeError: NoDiscard::__construct(): Argument #1 ($message) must be of type ?string, int given in %s:%d +Stack trace: +#0 %s(%d): NoDiscard->__construct(1234) +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/type_validation_003.phpt b/Zend/tests/attributes/nodiscard/type_validation_003.phpt new file mode 100644 index 0000000000000..0b66addaea187 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/type_validation_003.phpt @@ -0,0 +1,18 @@ +--TEST-- +#[\NoDiscard]: Type validation of $message parameter with array. +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught TypeError: NoDiscard::__construct(): Argument #1 ($message) must be of type ?string, array given in %s:%d +Stack trace: +#0 %s(%d): NoDiscard->__construct(Array) +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/type_validation_004.phpt b/Zend/tests/attributes/nodiscard/type_validation_004.phpt new file mode 100644 index 0000000000000..44d7c19b54863 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/type_validation_004.phpt @@ -0,0 +1,18 @@ +--TEST-- +#[\NoDiscard]: Type validation of $message parameter with native enum case. +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught TypeError: NoDiscard::__construct(): Argument #1 ($message) must be of type ?string, Random\IntervalBoundary given in %s:%d +Stack trace: +#0 %s(%d): NoDiscard->__construct(Random\IntervalBoundary::ClosedOpen) +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/unsupported_clone.phpt b/Zend/tests/attributes/nodiscard/unsupported_clone.phpt new file mode 100644 index 0000000000000..7fadfea40fa6a --- /dev/null +++ b/Zend/tests/attributes/nodiscard/unsupported_clone.phpt @@ -0,0 +1,16 @@ +--TEST-- +#[\NoDiscard]: Not allowed on '__clone'. +--FILE-- + +--EXPECTF-- +Fatal error: Method Clazz::__clone cannot be #[\NoDiscard] in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/unsupported_constructor.phpt b/Zend/tests/attributes/nodiscard/unsupported_constructor.phpt new file mode 100644 index 0000000000000..a11c6379938d3 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/unsupported_constructor.phpt @@ -0,0 +1,16 @@ +--TEST-- +#[\NoDiscard]: Not allowed on '__construct'. +--FILE-- + +--EXPECTF-- +Fatal error: Method Clazz::__construct cannot be #[\NoDiscard] in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/unsupported_never_function.phpt b/Zend/tests/attributes/nodiscard/unsupported_never_function.phpt new file mode 100644 index 0000000000000..ee7a81acbcde9 --- /dev/null +++ b/Zend/tests/attributes/nodiscard/unsupported_never_function.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\NoDiscard]: Not allowed on never function. +--FILE-- + +--EXPECTF-- +Fatal error: A never returning function does not return a value, but #[\NoDiscard] requires a return value in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/unsupported_property_hook_get.phpt b/Zend/tests/attributes/nodiscard/unsupported_property_hook_get.phpt new file mode 100644 index 0000000000000..ccedf3ede315a --- /dev/null +++ b/Zend/tests/attributes/nodiscard/unsupported_property_hook_get.phpt @@ -0,0 +1,20 @@ +--TEST-- +#[\NoDiscard]: Not allowed on 'get' property hook. +--FILE-- +test; + +?> +--EXPECTF-- +Fatal error: #[\NoDiscard] is not supported for property hooks in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/unsupported_property_hook_set.phpt b/Zend/tests/attributes/nodiscard/unsupported_property_hook_set.phpt new file mode 100644 index 0000000000000..351593f5250bb --- /dev/null +++ b/Zend/tests/attributes/nodiscard/unsupported_property_hook_set.phpt @@ -0,0 +1,20 @@ +--TEST-- +#[\NoDiscard]: Not allowed on 'set' property hook. +--FILE-- +test = $value; + } + } +} + +$cls = new Foo(); +$cls->test = 'foo'; + +?> +--EXPECTF-- +Fatal error: #[\NoDiscard] is not supported for property hooks in %s on line %d diff --git a/Zend/tests/attributes/nodiscard/unsupported_void_function.phpt b/Zend/tests/attributes/nodiscard/unsupported_void_function.phpt new file mode 100644 index 0000000000000..3c45f255473bc --- /dev/null +++ b/Zend/tests/attributes/nodiscard/unsupported_void_function.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\NoDiscard]: Not allowed on void function. +--FILE-- + +--EXPECTF-- +Fatal error: A void function does not return a value, but #[\NoDiscard] requires a return value in %s on line %d diff --git a/Zend/tests/closures/closure_const_expr/attributes.phpt b/Zend/tests/closures/closure_const_expr/attributes.phpt index c83b821d12969..e331bc2edd568 100644 --- a/Zend/tests/closures/closure_const_expr/attributes.phpt +++ b/Zend/tests/closures/closure_const_expr/attributes.phpt @@ -8,13 +8,13 @@ reflection #[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] class Attr { public function __construct(public Closure $value) { - $value('foo'); + $value('foo'); } } #[Attr(static function () { })] #[Attr(static function (...$args) { - var_dump($args); + var_dump($args); })] class C {} diff --git a/Zend/tests/closures/closure_const_expr/attributes_autoload.inc b/Zend/tests/closures/closure_const_expr/attributes_autoload.inc new file mode 100644 index 0000000000000..48f9b1987cf5d --- /dev/null +++ b/Zend/tests/closures/closure_const_expr/attributes_autoload.inc @@ -0,0 +1,9 @@ + diff --git a/Zend/tests/closures/closure_const_expr/attributes_autoload.phpt b/Zend/tests/closures/closure_const_expr/attributes_autoload.phpt new file mode 100644 index 0000000000000..fa99e8b5abaa3 --- /dev/null +++ b/Zend/tests/closures/closure_const_expr/attributes_autoload.phpt @@ -0,0 +1,57 @@ +--TEST-- +GH-17851: Use-after-free when instantiating autoloaded class with attribute having a Closure parameter. +--EXTENSIONS-- +reflection +--FILE-- +getAttributes() as $reflectionAttribute) { + var_dump($reflectionAttribute->newInstance()); +} + +?> +--EXPECTF-- +object(Attr)#%d (1) { + ["value"]=> + object(Closure)#%d (3) { + ["name"]=> + string(%d) "{closure:%s:%d}" + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) + } +} +array(1) { + [0]=> + string(3) "foo" +} +object(Attr)#%d (1) { + ["value"]=> + object(Closure)#%d (4) { + ["name"]=> + string(%d) "{closure:%s:%d}" + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) + ["parameter"]=> + array(1) { + ["$args"]=> + string(10) "" + } + } +} diff --git a/Zend/tests/closures/closure_const_expr/static_variable.phpt b/Zend/tests/closures/closure_const_expr/static_variable.phpt new file mode 100644 index 0000000000000..5aea594d8620b --- /dev/null +++ b/Zend/tests/closures/closure_const_expr/static_variable.phpt @@ -0,0 +1,77 @@ +--TEST-- +Closures in const expressions support static variables. +--FILE-- + +--EXPECTF-- +object(Closure)#%d (4) { + ["name"]=> + string(%d) "{closure:%s:%d}" + ["file"]=> + string(%d) "%s" + ["line"]=> + int(3) + ["static"]=> + array(2) { + ["x"]=> + array(0) { + } + ["i"]=> + int(1) + } +} +array(1) { + [0]=> + int(2) +} +array(2) { + [0]=> + int(2) + [1]=> + int(4) +} +array(3) { + [0]=> + int(2) + [1]=> + int(4) + [2]=> + int(8) +} +object(Closure)#%d (4) { + ["name"]=> + string(%d) "{closure:%s:%d}" + ["file"]=> + string(%d) "%s" + ["line"]=> + int(3) + ["static"]=> + array(2) { + ["x"]=> + array(3) { + [0]=> + int(2) + [1]=> + int(4) + [2]=> + int(8) + } + ["i"]=> + int(8) + } +} diff --git a/Zend/tests/constexpr/constant_expressions_cast.phpt b/Zend/tests/constexpr/constant_expressions_cast.phpt new file mode 100644 index 0000000000000..4431e2c08d6b0 --- /dev/null +++ b/Zend/tests/constexpr/constant_expressions_cast.phpt @@ -0,0 +1,64 @@ +--TEST-- +Constant expressions with cast +--FILE-- + 1]; +const T5 = (float) 5; +const T6 = (array) ""; +const T7 = (array) var_dump(...); +const T8 = (array) new X; +const T9 = (array) new DateTime; +const T10 = (int) new DateTime; + +var_dump(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); +?> +--EXPECTF-- +Warning: Array to string conversion in %s on line %d + +Warning: Object of class DateTime could not be converted to int in %s on line %d +int(0) +bool(true) +string(5) "Array" +object(stdClass)#%d (1) { + ["a"]=> + int(1) +} +float(5) +array(1) { + [0]=> + string(0) "" +} +array(1) { + [0]=> + object(Closure)#%d (2) { + ["function"]=> + string(8) "var_dump" + ["parameter"]=> + array(2) { + ["$value"]=> + string(10) "" + ["$values"]=> + string(10) "" + } + } +} +array(1) { + ["foo"]=> + int(3) +} +array(3) { + ["date"]=> + string(%d) "%s" + ["timezone_type"]=> + int(%d) + ["timezone"]=> + string(%d) "%s" +} +int(1) diff --git a/Zend/tests/constexpr/constant_expressions_cast_object_property.phpt b/Zend/tests/constexpr/constant_expressions_cast_object_property.phpt new file mode 100644 index 0000000000000..63616f0f8bf3b --- /dev/null +++ b/Zend/tests/constexpr/constant_expressions_cast_object_property.phpt @@ -0,0 +1,10 @@ +--TEST-- +Constant expressions with object cast in property +--FILE-- + +--EXPECTF-- +Fatal error: Object casts are not supported in this context in %s on line %d diff --git a/Zend/tests/declare/gh18033_1.phpt b/Zend/tests/declare/gh18033_1.phpt new file mode 100644 index 0000000000000..ccce9360b4651 --- /dev/null +++ b/Zend/tests/declare/gh18033_1.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-18033 (NULL-ptr dereference when using register_tick_function in destructor) +--DESCRIPTION-- +Needs --repeat 2 or something similar to reproduce +--CREDITS-- +clesmian +--FILE-- + +--EXPECT-- +Done +In destructor diff --git a/Zend/tests/declare/gh18033_2.phpt b/Zend/tests/declare/gh18033_2.phpt new file mode 100644 index 0000000000000..8fdcff1b51e6c --- /dev/null +++ b/Zend/tests/declare/gh18033_2.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-18033 (NULL-ptr dereference when using register_tick_function in ob_start) +--DESCRIPTION-- +Needs --repeat 2 or something similar to reproduce +--CREDITS-- +clesmian +--FILE-- + +--EXPECT-- diff --git a/Zend/tests/first_class_callable/gh18062.phpt b/Zend/tests/first_class_callable/gh18062.phpt new file mode 100644 index 0000000000000..3865dd77adba8 --- /dev/null +++ b/Zend/tests/first_class_callable/gh18062.phpt @@ -0,0 +1,32 @@ +--TEST-- +First Class Callable returns correct name from is_callable() +--FILE-- + +--EXPECT-- +string(9) "some_func" +string(13) "Foo::__invoke" +string(8) "Foo::bar" diff --git a/Zend/tests/get_error_handler.phpt b/Zend/tests/get_error_handler.phpt new file mode 100644 index 0000000000000..abe0b608a4cf9 --- /dev/null +++ b/Zend/tests/get_error_handler.phpt @@ -0,0 +1,88 @@ +--TEST-- +get_error_handler() +--FILE-- +handle(...)); +var_dump(get_error_handler() === $f); + +echo "\nClosure\n"; +set_error_handler($f = function () {}); +var_dump(get_error_handler() === $f); + +echo "\nInvokable\n"; +set_error_handler($object = new Invokable()); +var_dump(get_error_handler() === $object); + +echo "\nStable return value\n"; +var_dump(get_error_handler() === get_error_handler()); + +?> +==DONE== +--EXPECT-- +No error handler +bool(true) + +Function string +bool(true) + +NULL +bool(true) + +Static method array +bool(true) + +Static method string +bool(true) + +Instance method array +bool(true) + +First class callable method +bool(true) + +Closure +bool(true) + +Invokable +bool(true) + +Stable return value +bool(true) +==DONE== diff --git a/Zend/tests/get_exception_handler.phpt b/Zend/tests/get_exception_handler.phpt new file mode 100644 index 0000000000000..05f43db2c0f4c --- /dev/null +++ b/Zend/tests/get_exception_handler.phpt @@ -0,0 +1,87 @@ +--TEST-- +get_exception_handler() +--FILE-- +handle(...)); +var_dump(get_exception_handler() === $f); + +echo "\nClosure\n"; +set_exception_handler($f = function () {}); +var_dump(get_exception_handler() === $f); + +echo "\nInvokable\n"; +set_exception_handler($object = new Invokable()); +var_dump(get_exception_handler() === $object); + +echo "\nStable return value\n"; +var_dump(get_exception_handler() === get_exception_handler()); + +?>==DONE== +--EXPECT-- +No exception handler +bool(true) + +Function string +bool(true) + +NULL +bool(true) + +Static method array +bool(true) + +Static method string +bool(true) + +Instance method array +bool(true) + +First class callable method +bool(true) + +Closure +bool(true) + +Invokable +bool(true) + +Stable return value +bool(true) +==DONE== diff --git a/Zend/tests/gh18026.phpt b/Zend/tests/gh18026.phpt new file mode 100644 index 0000000000000..0e33e349b12fe --- /dev/null +++ b/Zend/tests/gh18026.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-18026: Confusing "amp" reference in parser error +--FILE-- + +--EXPECTF-- +Parse error: syntax error, unexpected token ")", expecting token "&" in %s on line %d diff --git a/Zend/tests/ghsa-rwp7-7vc6-8477_001.phpt b/Zend/tests/ghsa-rwp7-7vc6-8477_001.phpt new file mode 100644 index 0000000000000..d0e9ddcba410b --- /dev/null +++ b/Zend/tests/ghsa-rwp7-7vc6-8477_001.phpt @@ -0,0 +1,26 @@ +--TEST-- +GHSA-rwp7-7vc6-8477: Use-after-free for ??= due to incorrect live-range calculation +--FILE-- +foo()->baz ??= 1; +} catch (Exception $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +Hello diff --git a/Zend/tests/ghsa-rwp7-7vc6-8477_002.phpt b/Zend/tests/ghsa-rwp7-7vc6-8477_002.phpt new file mode 100644 index 0000000000000..4115d9eae26fd --- /dev/null +++ b/Zend/tests/ghsa-rwp7-7vc6-8477_002.phpt @@ -0,0 +1,24 @@ +--TEST-- +GHSA-rwp7-7vc6-8477: Use-after-free for ??= due to incorrect live-range calculation +--FILE-- +foo()->prop ??= 'foo'; +} catch (Error $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +Cannot assign string to property Foo::$prop of type int diff --git a/Zend/tests/ghsa-rwp7-7vc6-8477_003.phpt b/Zend/tests/ghsa-rwp7-7vc6-8477_003.phpt new file mode 100644 index 0000000000000..f2808afbf84de --- /dev/null +++ b/Zend/tests/ghsa-rwp7-7vc6-8477_003.phpt @@ -0,0 +1,22 @@ +--TEST-- +GHSA-rwp7-7vc6-8477: Use-after-free for ??= due to incorrect live-range calculation +--FILE-- +prop ??= 'foo'; +} catch (Error $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +Cannot assign string to property Foo::$prop of type int diff --git a/Zend/tests/lazy_objects/gh17941.phpt b/Zend/tests/lazy_objects/gh17941.phpt new file mode 100644 index 0000000000000..6af6355b99573 --- /dev/null +++ b/Zend/tests/lazy_objects/gh17941.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-17941 (Stack-use-after-return with lazy objects and hooks) +--FILE-- + $this->prop; set($x) => $this->prop = $x;} +} + +$rc = new ReflectionClass(SubClass::class); +$obj = $rc->newLazyProxy(function ($object) { + echo "init\n"; + return new SubClass; +}); + +function foo(SubClass $x) { + $x->prop = 1; + var_dump($x->prop); +} + +foo($obj); + +?> +--EXPECT-- +init +int(1) diff --git a/Zend/tests/lazy_objects/gh17998.phpt b/Zend/tests/lazy_objects/gh17998.phpt new file mode 100644 index 0000000000000..12d22b4704a13 --- /dev/null +++ b/Zend/tests/lazy_objects/gh17998.phpt @@ -0,0 +1,31 @@ +--TEST-- +GH-17998: Skipped lazy init on primed SIMPLE_WRITE +--FILE-- + $value; + } +} + +$nonLazy = new C; + +$lazy = (new ReflectionClass(C::class))->newLazyProxy(function () { + echo "init\n"; + return new C; +}); + +function foo(C $c) { + $c->prop = 1; + var_dump($c->prop); +} + +foo($nonLazy); +foo($lazy); + +?> +--EXPECT-- +int(1) +init +int(1) diff --git a/Zend/tests/lazy_objects/gh18038-001.phpt b/Zend/tests/lazy_objects/gh18038-001.phpt new file mode 100644 index 0000000000000..88e453c4a251f --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-001.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-18038 001: Lazy proxy calls magic methods twice +--FILE-- +$name = $value * 2; + } +} + +$rc = new ReflectionClass(C::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new C; +}); + +$obj->prop = 1; +var_dump($obj->prop); + +?> +--EXPECT-- +string(8) "C::__set" +init +int(2) diff --git a/Zend/tests/lazy_objects/gh18038-002.phpt b/Zend/tests/lazy_objects/gh18038-002.phpt new file mode 100644 index 0000000000000..4c12f21de8115 --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-002.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-18038 002: Lazy proxy calls magic methods twice +--FILE-- +$name = $value * 2; + unset($this->$name); + $this->$name = $value * 2; + } +} + +#[AllowDynamicProperties] +class Proxy extends RealInstance { +} + +$rc = new ReflectionClass(Proxy::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new RealInstance; +}); + +$real = $rc->initializeLazyObject($obj); +$real->prop = 1; +var_dump($obj->prop); + +?> +--EXPECT-- +init +string(19) "RealInstance::__set" +string(12) "Proxy::__set" +int(2) diff --git a/Zend/tests/lazy_objects/gh18038-003.phpt b/Zend/tests/lazy_objects/gh18038-003.phpt new file mode 100644 index 0000000000000..1db0588a70cfa --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-003.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-18038 003: Lazy proxy calls magic methods twice +--FILE-- +$name; + } +} + +$rc = new ReflectionClass(C::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new C; +}); + +var_dump($obj->prop); + +?> +--EXPECTF-- +string(8) "C::__get" +init + +Warning: Undefined property: C::$prop in %s on line %d +NULL diff --git a/Zend/tests/lazy_objects/gh18038-004.phpt b/Zend/tests/lazy_objects/gh18038-004.phpt new file mode 100644 index 0000000000000..8810efb6bec2e --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-004.phpt @@ -0,0 +1,45 @@ +--TEST-- +GH-18038 004: Lazy proxy calls magic methods twice +--FILE-- +$name); + return $this->$name; + } +} + +#[AllowDynamicProperties] +class Proxy extends RealInstance { + public function __get($name) { + var_dump(get_class($this)."::".__FUNCTION__); + return $this->$name; + } +} + +$rc = new ReflectionClass(Proxy::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new RealInstance; +}); + +$real = $rc->initializeLazyObject($obj); +var_dump($real->prop); + +?> +--EXPECTF-- +init +string(19) "RealInstance::__get" +string(12) "Proxy::__get" + +Warning: Undefined property: RealInstance::$prop in %s on line %d +NULL + +Warning: Undefined property: RealInstance::$prop in %s on line %d +NULL diff --git a/Zend/tests/lazy_objects/gh18038-005.phpt b/Zend/tests/lazy_objects/gh18038-005.phpt new file mode 100644 index 0000000000000..b728d45253daf --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-005.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-18038 005: Lazy proxy calls magic methods twice +--FILE-- +$name['']); + } +} + +$rc = new ReflectionClass(C::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new C; +}); + +var_dump(isset($obj->prop[''])); + +?> +--EXPECT-- +string(10) "C::__isset" +init +bool(false) diff --git a/Zend/tests/lazy_objects/gh18038-006.phpt b/Zend/tests/lazy_objects/gh18038-006.phpt new file mode 100644 index 0000000000000..256f0be8e202b --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-006.phpt @@ -0,0 +1,37 @@ +--TEST-- +GH-18038 006: Lazy proxy calls magic methods twice +--FILE-- +$name['']); + } + public function __get($name) { + var_dump(__METHOD__); + return $this->$name['']; + } +} + +$rc = new ReflectionClass(C::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new C; +}); + +var_dump(isset($obj->prop[''])); + +?> +--EXPECTF-- +string(10) "C::__isset" +string(8) "C::__get" +init + +Warning: Undefined property: C::$prop in %s on line %d + +Warning: Trying to access array offset on null in %s on line %d +bool(false) diff --git a/Zend/tests/lazy_objects/gh18038-007.phpt b/Zend/tests/lazy_objects/gh18038-007.phpt new file mode 100644 index 0000000000000..9925190a19801 --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-007.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-18038 007: Lazy proxy calls magic methods twice +--FILE-- +$name[''])); + return isset($this->$name['']); + } +} + +#[AllowDynamicProperties] +class Proxy extends RealInstance { + public function __isset($name) { + var_dump(get_class($this)."::".__FUNCTION__); + return isset($this->$name['']); + } +} + +$rc = new ReflectionClass(Proxy::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new RealInstance; +}); + +$real = $rc->initializeLazyObject($obj); +var_dump(isset($real->prop[''])); + +?> +--EXPECT-- +init +string(21) "RealInstance::__isset" +string(14) "Proxy::__isset" +bool(false) +bool(false) diff --git a/Zend/tests/lazy_objects/gh18038-008.phpt b/Zend/tests/lazy_objects/gh18038-008.phpt new file mode 100644 index 0000000000000..34d6e766163de --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-008.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-18038 008: Lazy proxy calls magic methods twice +--FILE-- +$name); + } +} + +$rc = new ReflectionClass(C::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new C; +}); + +var_dump(isset($obj->prop)); + +?> +--EXPECT-- +string(10) "C::__isset" +init +bool(false) diff --git a/Zend/tests/lazy_objects/gh18038-009.phpt b/Zend/tests/lazy_objects/gh18038-009.phpt new file mode 100644 index 0000000000000..3c165a71ccffe --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-009.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-18038 009: Lazy proxy calls magic methods twice +--FILE-- +$name)); + return isset($this->$name); + } +} + +#[AllowDynamicProperties] +class Proxy extends RealInstance { + public function __isset($name) { + var_dump(get_class($this)."::".__FUNCTION__); + return isset($this->$name); + } +} + +$rc = new ReflectionClass(Proxy::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new RealInstance; +}); + +$real = $rc->initializeLazyObject($obj); +var_dump(isset($real->prop)); + +?> +--EXPECT-- +init +string(21) "RealInstance::__isset" +string(14) "Proxy::__isset" +bool(false) +bool(false) diff --git a/Zend/tests/lazy_objects/gh18038-010.phpt b/Zend/tests/lazy_objects/gh18038-010.phpt new file mode 100644 index 0000000000000..584c18580a210 --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-010.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-18038 010: Lazy proxy calls magic methods twice +--FILE-- +$name); + } +} + +$rc = new ReflectionClass(C::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new C; +}); + +unset($obj->prop); +var_dump($obj); + +?> +--EXPECTF-- +string(10) "C::__unset" +init +lazy proxy object(C)#%d (1) { + ["instance"]=> + object(C)#%d (1) { + ["_"]=> + NULL + } +} diff --git a/Zend/tests/lazy_objects/gh18038-011.phpt b/Zend/tests/lazy_objects/gh18038-011.phpt new file mode 100644 index 0000000000000..b356f9e4f384d --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-011.phpt @@ -0,0 +1,45 @@ +--TEST-- +GH-18038 011: Lazy proxy calls magic methods twice +--FILE-- +$name); + } +} + +#[AllowDynamicProperties] +class Proxy extends RealInstance { + public function __isset($name) { + var_dump(get_class($this)."::".__FUNCTION__); + unset($this->$name); + } +} + +$rc = new ReflectionClass(Proxy::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new RealInstance; +}); + +$real = $rc->initializeLazyObject($obj); +unset($real->prop); +var_dump($obj); + +?> +--EXPECTF-- +init +string(21) "RealInstance::__unset" +lazy proxy object(Proxy)#%d (1) { + ["instance"]=> + object(RealInstance)#%d (1) { + ["_"]=> + NULL + } +} diff --git a/Zend/tests/lazy_objects/gh18038-012.phpt b/Zend/tests/lazy_objects/gh18038-012.phpt new file mode 100644 index 0000000000000..5bc83333d81c7 --- /dev/null +++ b/Zend/tests/lazy_objects/gh18038-012.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-18038 012: Lazy proxy calls magic methods twice +--FILE-- +$name = $value * 2; + } +} + +$rc = new ReflectionClass(C::class); + +$obj = $rc->newLazyGhost(function () { + echo "init\n"; +}); + +$obj->prop = 1; +var_dump($obj->prop); + +?> +--EXPECT-- +string(8) "C::__set" +init +int(2) diff --git a/Zend/tests/oss-fuzz-403816122.phpt b/Zend/tests/oss-fuzz-403816122.phpt new file mode 100644 index 0000000000000..b9d9400609fc6 --- /dev/null +++ b/Zend/tests/oss-fuzz-403816122.phpt @@ -0,0 +1,22 @@ +--TEST-- +OSS-Fuzz #403816122: Segfault when initializing default properties of child prop with added hooks +--FILE-- + 'y'; + } +} + +var_dump((new C)->prop); + +?> +--EXPECT-- +string(1) "y" diff --git a/Zend/tests/oss_fuzz_410939023.phpt b/Zend/tests/oss_fuzz_410939023.phpt new file mode 100644 index 0000000000000..9c024bf5b5b06 --- /dev/null +++ b/Zend/tests/oss_fuzz_410939023.phpt @@ -0,0 +1,11 @@ +--TEST-- +OSS-Fuzz #410939023: Use of magic const within const expr cast +--FILE-- + +--EXPECT-- +string(0) "" diff --git a/Zend/tests/property_hooks/gh17988.phpt b/Zend/tests/property_hooks/gh17988.phpt new file mode 100644 index 0000000000000..629eec60d010b --- /dev/null +++ b/Zend/tests/property_hooks/gh17988.phpt @@ -0,0 +1,40 @@ +--TEST-- +GH-17988: Incorrect handling of hooked properties without get hook in get_object_vars() +--FILE-- + $value; + } +} + +$c = new C; +$c->prop = 42; + +var_dump($c); +var_dump(get_object_vars($c)); +var_export($c); +echo "\n"; +var_dump(json_encode($c)); +var_dump((array)$c); + +?> +--EXPECTF-- +object(C)#%d (1) { + ["prop"]=> + string(2) "42" +} +array(1) { + ["prop"]=> + string(2) "42" +} +\C::__set_state(array( + 'prop' => '42', +)) +string(13) "{"prop":"42"}" +array(1) { + ["prop"]=> + string(2) "42" +} diff --git a/Zend/tests/property_hooks/gh18000.phpt b/Zend/tests/property_hooks/gh18000.phpt new file mode 100644 index 0000000000000..61b36034671f9 --- /dev/null +++ b/Zend/tests/property_hooks/gh18000.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-18000: Lazy proxy calls set hook twice +--FILE-- +prop = $value * 2; + } + } +} + +$rc = new ReflectionClass(C::class); + +$obj = $rc->newLazyProxy(function () { + echo "init\n"; + return new C; +}); + +function foo(C $c) { + $c->prop = 1; + var_dump($c->prop); +} + +foo($obj); + +?> +--EXPECT-- +set +init +int(2) diff --git a/Zend/tests/property_hooks/gh18268.phpt b/Zend/tests/property_hooks/gh18268.phpt new file mode 100644 index 0000000000000..9836bb6d96270 --- /dev/null +++ b/Zend/tests/property_hooks/gh18268.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-18268: array_walk() on object with added property hooks +--FILE-- + +--EXPECT-- +int(42) diff --git a/Zend/tests/property_hooks/oss_fuzz_403308724.phpt b/Zend/tests/property_hooks/oss_fuzz_403308724.phpt new file mode 100644 index 0000000000000..b27b08dd703b6 --- /dev/null +++ b/Zend/tests/property_hooks/oss_fuzz_403308724.phpt @@ -0,0 +1,30 @@ +--TEST-- +OSS-Fuzz #403308724 +--FILE-- + 1; } +} + +class Test extends Base { + public $y { + get => [new class { + public $inner {get => __PROPERTY__;} + }, parent::$y::get()]; + } +} + +$test = new Test; +$y = $test->y; +var_dump($y); +var_dump($y[0]->inner); +?> +--EXPECT-- +array(2) { + [0]=> + object(class@anonymous)#2 (0) { + } + [1]=> + int(1) +} +string(5) "inner" diff --git a/Zend/tests/traits/bugs/missing-trait.phpt b/Zend/tests/traits/bugs/missing-trait.phpt index 4bf054e889002..0b36c47e771d7 100644 --- a/Zend/tests/traits/bugs/missing-trait.phpt +++ b/Zend/tests/traits/bugs/missing-trait.phpt @@ -12,4 +12,7 @@ $test = new TraitsTest(); ?> --EXPECTF-- -Fatal error: Trait "THello" not found in %s on line %d +Fatal error: Uncaught Error: Trait "THello" not found in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/traits/constant_015.phpt b/Zend/tests/traits/constant_015.phpt index 24507ea9e59cd..1b219340506b8 100644 --- a/Zend/tests/traits/constant_015.phpt +++ b/Zend/tests/traits/constant_015.phpt @@ -1,5 +1,5 @@ --TEST-- -The same name constant of a trait used in a class that inherits a constant defined in a parent can be defined only if they are compatible. +Final class constant in parent may not be overridden by child through trait --FILE-- --EXPECTF-- -Fatal error: BaseClass2 and TestTrait2 define the same constant (Constant) in the composition of DerivedClass2. However, the definition differs and is considered incompatible. Class was composed in %s on line %d +Fatal error: DerivedClass1::Constant cannot override final constant BaseClass1::Constant in %s on line %d diff --git a/Zend/tests/traits/error_001.phpt b/Zend/tests/traits/error_001.phpt deleted file mode 100644 index a7889da41e2b7..0000000000000 --- a/Zend/tests/traits/error_001.phpt +++ /dev/null @@ -1,28 +0,0 @@ ---TEST-- -Trying to use instanceof for a method twice ---FILE-- - ---EXPECTF-- -Fatal error: Class A cannot extend trait foo in %s on line %d diff --git a/Zend/tests/traits/error_002.phpt b/Zend/tests/traits/error_002.phpt index 53ad403a43373..fc9cfc5884c4c 100644 --- a/Zend/tests/traits/error_002.phpt +++ b/Zend/tests/traits/error_002.phpt @@ -9,4 +9,7 @@ class A { ?> --EXPECTF-- -Fatal error: Trait "abc" not found in %s on line %d +Fatal error: Uncaught Error: Trait "abc" not found in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/traits/error_003.phpt b/Zend/tests/traits/error_003.phpt index fdfa0ac1fe22b..6a6d2d56d6c41 100644 --- a/Zend/tests/traits/error_003.phpt +++ b/Zend/tests/traits/error_003.phpt @@ -12,4 +12,7 @@ class A { ?> --EXPECTF-- -Fatal error: A cannot use abc - it is not a trait in %s on line %d +Fatal error: Uncaught Error: A cannot use abc - it is not a trait in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/traits/error_004.phpt b/Zend/tests/traits/error_004.phpt index d7ff695e047b3..1e339f3d6314d 100644 --- a/Zend/tests/traits/error_004.phpt +++ b/Zend/tests/traits/error_004.phpt @@ -12,4 +12,7 @@ class A { ?> --EXPECTF-- -Fatal error: A cannot use abc - it is not a trait in %s on line %d +Fatal error: Uncaught Error: A cannot use abc - it is not a trait in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/traits/error_005.phpt b/Zend/tests/traits/error_005.phpt index 3b8cc32f97584..dae8e1893a68c 100644 --- a/Zend/tests/traits/error_005.phpt +++ b/Zend/tests/traits/error_005.phpt @@ -12,4 +12,7 @@ class A { ?> --EXPECTF-- -Fatal error: A cannot use abc - it is not a trait in %s on line %d +Fatal error: Uncaught Error: A cannot use abc - it is not a trait in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/traits/error_006.phpt b/Zend/tests/traits/error_006.phpt index f3ed87123cf29..5d831a9da7f12 100644 --- a/Zend/tests/traits/error_006.phpt +++ b/Zend/tests/traits/error_006.phpt @@ -12,4 +12,7 @@ class A { ?> --EXPECTF-- -Fatal error: A cannot use abc - it is not a trait in %s on line %d +Fatal error: Uncaught Error: A cannot use abc - it is not a trait in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/traits/gh15753.phpt b/Zend/tests/traits/gh15753.phpt new file mode 100644 index 0000000000000..21e32d96c09e3 --- /dev/null +++ b/Zend/tests/traits/gh15753.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-15753: Trait can override property declared in parent class of used class +--FILE-- +prop); + +?> +--EXPECT-- +int(2) diff --git a/Zend/tests/traits/gh16198.phpt b/Zend/tests/traits/gh16198.phpt new file mode 100644 index 0000000000000..f44926cf5ce24 --- /dev/null +++ b/Zend/tests/traits/gh16198.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-16198: Incorrect trait constant conflict when declared via trait +--FILE-- + +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/tests/traits/gh16198_2.phpt b/Zend/tests/traits/gh16198_2.phpt new file mode 100644 index 0000000000000..7599ea1a11b49 --- /dev/null +++ b/Zend/tests/traits/gh16198_2.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-16198: Usage of super in cloned trait method +--FILE-- + +--EXPECT-- +string(13) "P::__destruct" diff --git a/Zend/tests/traits/gh17959.phpt b/Zend/tests/traits/gh17959.phpt new file mode 100644 index 0000000000000..016dd7a4a4f7c --- /dev/null +++ b/Zend/tests/traits/gh17959.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-17959: Missing trait error is recoverable +--FILE-- +getMessage(), "\n"; +} + +?> +===DONE=== +--EXPECT-- +Error: Trait "MissingTrait" not found +===DONE=== diff --git a/Zend/tests/type_casts/cast_to_void.phpt b/Zend/tests/type_casts/cast_to_void.phpt new file mode 100644 index 0000000000000..cdbcffad519c9 --- /dev/null +++ b/Zend/tests/type_casts/cast_to_void.phpt @@ -0,0 +1,47 @@ +--TEST-- +casting different variables to void +--FILE-- + +--EXPECTF-- +Done diff --git a/Zend/tests/type_casts/cast_to_void_ast.phpt b/Zend/tests/type_casts/cast_to_void_ast.phpt new file mode 100644 index 0000000000000..26911bddb7ebc --- /dev/null +++ b/Zend/tests/type_casts/cast_to_void_ast.phpt @@ -0,0 +1,18 @@ +--TEST-- +(void) is included in AST printing +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +assert(false && function () { + (void)somefunc(); +}) diff --git a/Zend/tests/type_casts/cast_to_void_destructor.phpt b/Zend/tests/type_casts/cast_to_void_destructor.phpt new file mode 100644 index 0000000000000..027e4b77e5dda --- /dev/null +++ b/Zend/tests/type_casts/cast_to_void_destructor.phpt @@ -0,0 +1,30 @@ +--TEST-- +casting to void destroys the value. +--FILE-- + +--EXPECT-- +Before +WithDestructor::__destruct +After diff --git a/Zend/tests/type_casts/cast_to_void_statement.phpt b/Zend/tests/type_casts/cast_to_void_statement.phpt new file mode 100644 index 0000000000000..3262e1efd549c --- /dev/null +++ b/Zend/tests/type_casts/cast_to_void_statement.phpt @@ -0,0 +1,11 @@ +--TEST-- +casting to void is a statement +--FILE-- + +--EXPECTF-- +Parse error: syntax error, unexpected token "(void)" in %s on line %d diff --git a/Zend/tests/type_casts/gh18301_cast_to_void_for.phpt b/Zend/tests/type_casts/gh18301_cast_to_void_for.phpt new file mode 100644 index 0000000000000..2ff7cfb0cb17b --- /dev/null +++ b/Zend/tests/type_casts/gh18301_cast_to_void_for.phpt @@ -0,0 +1,46 @@ +--TEST-- +GH-18301: casting to void is allowed in for’s expression lists +--FILE-- + +--EXPECTF-- +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d +4 + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d +10 + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d +16 + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d +22 + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d +28 + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d diff --git a/Zend/tests/type_casts/gh18301_cast_to_void_statement_for_condition.phpt b/Zend/tests/type_casts/gh18301_cast_to_void_statement_for_condition.phpt new file mode 100644 index 0000000000000..6c90b2f7987c6 --- /dev/null +++ b/Zend/tests/type_casts/gh18301_cast_to_void_statement_for_condition.phpt @@ -0,0 +1,9 @@ +--TEST-- +GH-18301: casting to void is not allowed at the end of a for condition +--FILE-- + +--EXPECTF-- +Parse error: syntax error, unexpected token ";", expecting "," in %s on line %d diff --git a/Zend/tests/type_declarations/scalar_return_basic.phpt b/Zend/tests/type_declarations/scalar_return_basic.phpt index 1fd3d26db6d8a..8f827600328ed 100644 --- a/Zend/tests/type_declarations/scalar_return_basic.phpt +++ b/Zend/tests/type_declarations/scalar_return_basic.phpt @@ -44,7 +44,7 @@ $values = [ [], new StdClass, new StringCapable, - fopen("data:text/plain,foobar", "r") + STDERR, ]; foreach ($functions as $type => $function) { @@ -92,13 +92,13 @@ int(0) *** Trying array(0) { } *** Caught {closure:%s:%d}(): Return value must be of type int, array returned in %s on line %d -*** Trying object(stdClass)#6 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type int, stdClass returned in %s on line %d -*** Trying object(StringCapable)#7 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type int, StringCapable returned in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Return value must be of type int, resource returned in %s on line %d Testing 'float' type: @@ -129,13 +129,13 @@ float(0) *** Trying array(0) { } *** Caught {closure:%s:%d}(): Return value must be of type float, array returned in %s on line %d -*** Trying object(stdClass)#6 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type float, stdClass returned in %s on line %d -*** Trying object(StringCapable)#7 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type float, StringCapable returned in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Return value must be of type float, resource returned in %s on line %d Testing 'string' type: @@ -166,13 +166,13 @@ string(0) "" *** Trying array(0) { } *** Caught {closure:%s:%d}(): Return value must be of type string, array returned in %s on line %d -*** Trying object(stdClass)#6 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type string, stdClass returned in %s on line %d -*** Trying object(StringCapable)#7 (0) { +*** Trying object(StringCapable)#%d (0) { } string(6) "foobar" -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Return value must be of type string, resource returned in %s on line %d Testing 'bool' type: @@ -203,13 +203,13 @@ bool(false) *** Trying array(0) { } *** Caught {closure:%s:%d}(): Return value must be of type bool, array returned in %s on line %d -*** Trying object(stdClass)#6 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type bool, stdClass returned in %s on line %d -*** Trying object(StringCapable)#7 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type bool, StringCapable returned in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Return value must be of type bool, resource returned in %s on line %d Done diff --git a/Zend/tests/type_declarations/scalar_return_basic_64bit.phpt b/Zend/tests/type_declarations/scalar_return_basic_64bit.phpt index da930b98d9b65..0a32dd3f16f23 100644 --- a/Zend/tests/type_declarations/scalar_return_basic_64bit.phpt +++ b/Zend/tests/type_declarations/scalar_return_basic_64bit.phpt @@ -44,7 +44,7 @@ $values = [ [], new StdClass, new StringCapable, - fopen("data:text/plain,foobar", "r") + STDERR, ]; foreach ($functions as $type => $function) { @@ -92,13 +92,13 @@ int(0) *** Trying array(0) { } *** Caught {closure:%s:%d}(): Return value must be of type int, array returned in %s on line %d -*** Trying object(stdClass)#6 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type int, stdClass returned in %s on line %d -*** Trying object(StringCapable)#7 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type int, StringCapable returned in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Return value must be of type int, resource returned in %s on line %d Testing 'float' type: @@ -129,13 +129,13 @@ float(0) *** Trying array(0) { } *** Caught {closure:%s:%d}(): Return value must be of type float, array returned in %s on line %d -*** Trying object(stdClass)#6 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type float, stdClass returned in %s on line %d -*** Trying object(StringCapable)#7 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type float, StringCapable returned in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Return value must be of type float, resource returned in %s on line %d Testing 'string' type: @@ -166,13 +166,13 @@ string(0) "" *** Trying array(0) { } *** Caught {closure:%s:%d}(): Return value must be of type string, array returned in %s on line %d -*** Trying object(stdClass)#6 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type string, stdClass returned in %s on line %d -*** Trying object(StringCapable)#7 (0) { +*** Trying object(StringCapable)#%d (0) { } string(6) "foobar" -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Return value must be of type string, resource returned in %s on line %d Testing 'bool' type: @@ -203,13 +203,13 @@ bool(false) *** Trying array(0) { } *** Caught {closure:%s:%d}(): Return value must be of type bool, array returned in %s on line %d -*** Trying object(stdClass)#6 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type bool, stdClass returned in %s on line %d -*** Trying object(StringCapable)#7 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Return value must be of type bool, StringCapable returned in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Return value must be of type bool, resource returned in %s on line %d Done diff --git a/Zend/tests/type_declarations/scalar_strict.phpt b/Zend/tests/type_declarations/scalar_strict.phpt index e89d18b2c86b3..626f322d8701f 100644 --- a/Zend/tests/type_declarations/scalar_strict.phpt +++ b/Zend/tests/type_declarations/scalar_strict.phpt @@ -96,15 +96,15 @@ int(2147483647) } *** Caught {closure:%s:%d}(): Argument #1 ($i) must be of type int, array given, called in %s on line %d -*** Trying object(stdClass)#5 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($i) must be of type int, stdClass given, called in %s on line %d -*** Trying object(StringCapable)#6 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($i) must be of type int, StringCapable given, called in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Argument #1 ($i) must be of type int, resource given, called in %s on line %d Testing 'float' type: @@ -149,15 +149,15 @@ float(NAN) } *** Caught {closure:%s:%d}(): Argument #1 ($f) must be of type float, array given, called in %s on line %d -*** Trying object(stdClass)#5 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($f) must be of type float, stdClass given, called in %s on line %d -*** Trying object(StringCapable)#6 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($f) must be of type float, StringCapable given, called in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Argument #1 ($f) must be of type float, resource given, called in %s on line %d Testing 'string' type: @@ -202,15 +202,15 @@ string(0) "" } *** Caught {closure:%s:%d}(): Argument #1 ($s) must be of type string, array given, called in %s on line %d -*** Trying object(stdClass)#5 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($s) must be of type string, stdClass given, called in %s on line %d -*** Trying object(StringCapable)#6 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($s) must be of type string, StringCapable given, called in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Argument #1 ($s) must be of type string, resource given, called in %s on line %d Testing 'bool' type: @@ -255,15 +255,15 @@ bool(false) } *** Caught {closure:%s:%d}(): Argument #1 ($b) must be of type bool, array given, called in %s on line %d -*** Trying object(stdClass)#5 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($b) must be of type bool, stdClass given, called in %s on line %d -*** Trying object(StringCapable)#6 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($b) must be of type bool, StringCapable given, called in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Argument #1 ($b) must be of type bool, resource given, called in %s on line %d Done diff --git a/Zend/tests/type_declarations/scalar_strict_64bit.phpt b/Zend/tests/type_declarations/scalar_strict_64bit.phpt index 6335e2d1acee4..b7f2ce0de4396 100644 --- a/Zend/tests/type_declarations/scalar_strict_64bit.phpt +++ b/Zend/tests/type_declarations/scalar_strict_64bit.phpt @@ -35,7 +35,7 @@ $values = [ [], new StdClass, new StringCapable, - fopen("data:text/plain,foobar", "r") + STDERR, ]; foreach ($functions as $type => $function) { @@ -96,15 +96,15 @@ int(9223372036854775807) } *** Caught {closure:%s:%d}(): Argument #1 ($i) must be of type int, array given, called in %s on line %d -*** Trying object(stdClass)#5 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($i) must be of type int, stdClass given, called in %s on line %d -*** Trying object(StringCapable)#6 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($i) must be of type int, StringCapable given, called in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Argument #1 ($i) must be of type int, resource given, called in %s on line %d Testing 'float' type: @@ -149,15 +149,15 @@ float(NAN) } *** Caught {closure:%s:%d}(): Argument #1 ($f) must be of type float, array given, called in %s on line %d -*** Trying object(stdClass)#5 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($f) must be of type float, stdClass given, called in %s on line %d -*** Trying object(StringCapable)#6 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($f) must be of type float, StringCapable given, called in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Argument #1 ($f) must be of type float, resource given, called in %s on line %d Testing 'string' type: @@ -202,15 +202,15 @@ string(0) "" } *** Caught {closure:%s:%d}(): Argument #1 ($s) must be of type string, array given, called in %s on line %d -*** Trying object(stdClass)#5 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($s) must be of type string, stdClass given, called in %s on line %d -*** Trying object(StringCapable)#6 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($s) must be of type string, StringCapable given, called in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Argument #1 ($s) must be of type string, resource given, called in %s on line %d Testing 'bool' type: @@ -255,15 +255,15 @@ bool(false) } *** Caught {closure:%s:%d}(): Argument #1 ($b) must be of type bool, array given, called in %s on line %d -*** Trying object(stdClass)#5 (0) { +*** Trying object(stdClass)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($b) must be of type bool, stdClass given, called in %s on line %d -*** Trying object(StringCapable)#6 (0) { +*** Trying object(StringCapable)#%d (0) { } *** Caught {closure:%s:%d}(): Argument #1 ($b) must be of type bool, StringCapable given, called in %s on line %d -*** Trying resource(5) of type (stream) +*** Trying resource(%d) of type (stream) *** Caught {closure:%s:%d}(): Argument #1 ($b) must be of type bool, resource given, called in %s on line %d Done diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 32c9f4613ae9b..e0006e7d7275f 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -22,6 +22,7 @@ #include "zend.h" #include "zend_execute.h" #include "zend_API.h" +#include "zend_hash.h" #include "zend_modules.h" #include "zend_extensions.h" #include "zend_constants.h" @@ -1438,7 +1439,7 @@ ZEND_API HashTable *zend_separate_class_constants_table(zend_class_entry *class_ ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&class_type->constants_table, key, c) { if (c->ce == class_type) { - if (Z_TYPE(c->value) == IS_CONSTANT_AST) { + if (Z_TYPE(c->value) == IS_CONSTANT_AST || (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED)) { new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant)); memcpy(new_c, c, sizeof(zend_class_constant)); c = new_c; @@ -1612,8 +1613,12 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) / /* Use the default properties table to also update initializers of private properties * that have been shadowed in a child class. */ for (uint32_t i = 0; i < class_type->default_properties_count; i++) { - val = &default_properties_table[i]; prop_info = class_type->properties_info_table[i]; + if (!prop_info) { + continue; + } + + val = &default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]; if (Z_TYPE_P(val) == IS_CONSTANT_AST && UNEXPECTED(update_property(val, prop_info) != SUCCESS)) { return FAILURE; @@ -2693,6 +2698,12 @@ static void zend_check_magic_method_arg_type(uint32_t arg_num, const zend_class_ static void zend_check_magic_method_return_type(const zend_class_entry *ce, const zend_function *fptr, int error_type, int return_type) { + if (return_type == MAY_BE_VOID) { + if (fptr->common.fn_flags & ZEND_ACC_NODISCARD) { + zend_error_noreturn(error_type, "Method %s::%s cannot be #[\\NoDiscard]", ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name)); + } + } + if (!(fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) { /* For backwards compatibility reasons, do not enforce the return type if it is not set. */ return; @@ -2752,6 +2763,10 @@ static void zend_check_magic_method_no_return_type( zend_error_noreturn(error_type, "Method %s::%s() cannot declare a return type", ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name)); } + + if (fptr->common.fn_flags & ZEND_ACC_NODISCARD) { + zend_error_noreturn(error_type, "Method %s::%s cannot be #[\\NoDiscard]", ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name)); + } } ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, zend_string *lcname, int error_type) /* {{{ */ @@ -2899,14 +2914,14 @@ static zend_always_inline void zend_normalize_internal_type(zend_type *type) { ZEND_ASSERT(!ZEND_TYPE_CONTAINS_CODE(*type, IS_RESOURCE) && "resource is not allowed in a zend_type"); } zend_type *current; - ZEND_TYPE_FOREACH(*type, current) { + ZEND_TYPE_FOREACH_MUTABLE(*type, current) { if (ZEND_TYPE_HAS_NAME(*current)) { zend_string *name = zend_new_interned_string(ZEND_TYPE_NAME(*current)); zend_alloc_ce_cache(name); ZEND_TYPE_SET_PTR(*current, name); } else if (ZEND_TYPE_HAS_LIST(*current)) { zend_type *inner; - ZEND_TYPE_FOREACH(*current, inner) { + ZEND_TYPE_FOREACH_MUTABLE(*current, inner) { ZEND_ASSERT(!ZEND_TYPE_HAS_LITERAL_NAME(*inner) && !ZEND_TYPE_HAS_LIST(*inner)); if (ZEND_TYPE_HAS_NAME(*inner)) { zend_string *name = zend_new_interned_string(ZEND_TYPE_NAME(*inner)); @@ -3263,21 +3278,17 @@ ZEND_API zend_result zend_get_module_started(const char *module_name) /* {{{ */ } /* }}} */ -static int clean_module_class(zval *el, void *arg) /* {{{ */ -{ - zend_class_entry *ce = (zend_class_entry *)Z_PTR_P(el); - int module_number = *(int *)arg; - if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module->module_number == module_number) { - return ZEND_HASH_APPLY_REMOVE; - } else { - return ZEND_HASH_APPLY_KEEP; - } -} -/* }}} */ - static void clean_module_classes(int module_number) /* {{{ */ { - zend_hash_apply_with_argument(EG(class_table), clean_module_class, (void *) &module_number); + /* Child classes may reuse structures from parent classes, so destroy in reverse order. */ + Bucket *bucket; + ZEND_HASH_REVERSE_FOREACH_BUCKET(EG(class_table), bucket) { + zend_class_entry *ce = Z_CE(bucket->val); + if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module->module_number == module_number) { + zend_hash_del_bucket(EG(class_table), bucket); + } + } ZEND_HASH_FOREACH_END(); + } /* }}} */ @@ -4137,6 +4148,19 @@ ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, zend_object *obj case IS_OBJECT: { zend_class_entry *ce = Z_OBJCE_P(callable); + + if (ce == zend_ce_closure) { + const zend_function *fn = zend_get_closure_method_def(Z_OBJ_P(callable)); + + if (fn->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) { + if (fn->common.scope) { + return zend_create_member_string(fn->common.scope->name, fn->common.function_name); + } else { + return zend_string_copy(fn->common.function_name); + } + } + } + return zend_string_concat2( ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), "::__invoke", sizeof("::__invoke") - 1); diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 6aeffce25d8e5..a644de8e15134 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -690,8 +690,13 @@ ZEND_API zend_result _call_user_function_impl(zval *object, zval *function_name, #define call_user_function_named(function_table, object, function_name, retval_ptr, param_count, params, named_params) \ _call_user_function_impl(object, function_name, retval_ptr, param_count, params, named_params) -ZEND_API extern const zend_fcall_info empty_fcall_info; -ZEND_API extern const zend_fcall_info_cache empty_fcall_info_cache; +#ifndef __cplusplus +# define empty_fcall_info (zend_fcall_info) {0} +# define empty_fcall_info_cache (zend_fcall_info_cache) {0} +#else +# define empty_fcall_info zend_fcall_info {0} +# define empty_fcall_info_cache zend_fcall_info_cache {0} +#endif /** Build zend_call_info/cache from a zval* * @@ -800,7 +805,7 @@ static zend_always_inline void zend_fcc_dtor(zend_fcall_info_cache *fcc) if (fcc->closure) { OBJ_RELEASE(fcc->closure); } - memcpy(fcc, &empty_fcall_info_cache, sizeof(zend_fcall_info_cache)); + *fcc = empty_fcall_info_cache; } ZEND_API void zend_get_callable_zval_from_fcc(const zend_fcall_info_cache *fcc, zval *callable); diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 12e322d0347b3..b9f3bc015217c 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -305,7 +305,17 @@ struct _zend_mm_heap { size_t (*_gc)(void); void (*_shutdown)(bool full, bool silent); } custom_heap; - HashTable *tracked_allocs; + union { + HashTable *tracked_allocs; + struct { + bool poison_alloc; + uint8_t poison_alloc_value; + bool poison_free; + uint8_t poison_free_value; + uint8_t padding; + bool check_freelists_on_shutdown; + } debug; + }; #endif pid_t pid; zend_random_bytes_insecure_state rand_state; @@ -2389,8 +2399,19 @@ static void zend_mm_check_leaks(zend_mm_heap *heap) #if ZEND_MM_CUSTOM static void *tracked_malloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); static void tracked_free_all(zend_mm_heap *heap); +static void *poison_malloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); #endif +static void zend_mm_check_freelists(zend_mm_heap *heap) +{ + for (uint32_t bin_num = 0; bin_num < ZEND_MM_BINS; bin_num++) { + zend_mm_free_slot *slot = heap->free_slot[bin_num]; + while (slot) { + slot = zend_mm_get_next_free_slot(heap, bin_num, slot); + } + } +} + ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent) { zend_mm_chunk *p; @@ -2555,8 +2576,9 @@ ZEND_API size_t ZEND_FASTCALL _zend_mm_block_size(zend_mm_heap *heap, void *ptr if (size_zv) { return Z_LVAL_P(size_zv); } + } else if (heap->custom_heap._malloc != poison_malloc) { + return 0; } - return 0; } #endif return zend_mm_size(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); @@ -3021,6 +3043,200 @@ static void tracked_free_all(zend_mm_heap *heap) { } #endif +static void* poison_malloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) +{ + zend_mm_heap *heap = AG(mm_heap); + + if (SIZE_MAX - heap->debug.padding * 2 < size) { + zend_mm_panic("Integer overflow in memory allocation"); + } + size += heap->debug.padding * 2; + + void *ptr = zend_mm_alloc_heap(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + + if (EXPECTED(ptr)) { + if (heap->debug.poison_alloc) { + memset(ptr, heap->debug.poison_alloc_value, size); + } + + ptr = (char*)ptr + heap->debug.padding; + } + + return ptr; +} + +static void poison_free(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) +{ + zend_mm_heap *heap = AG(mm_heap); + + if (EXPECTED(ptr)) { + /* zend_mm_shutdown() will try to free the heap when custom handlers + * are installed */ + if (UNEXPECTED(ptr == heap)) { + return; + } + + ptr = (char*)ptr - heap->debug.padding; + + size_t size = zend_mm_size(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + + if (heap->debug.poison_free) { + memset(ptr, heap->debug.poison_free_value, size); + } + } + + zend_mm_free_heap(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); +} + +static void* poison_realloc(void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) +{ + zend_mm_heap *heap = AG(mm_heap); + + void *new = poison_malloc(size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + + if (ptr) { + /* Determine the size of the old allocation from the unpadded pointer. */ + size_t oldsize = zend_mm_size(heap, (char*)ptr - heap->debug.padding ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + + /* Remove the padding size to determine the size that is available to the user. */ + oldsize -= (2 * heap->debug.padding); + +#if ZEND_DEBUG + oldsize -= sizeof(zend_mm_debug_info); +#endif + + memcpy(new, ptr, MIN(oldsize, size)); + poison_free(ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + } + + return new; +} + +static size_t poison_gc(void) +{ + zend_mm_heap *heap = AG(mm_heap); + + void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); + void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); + void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); + size_t (*_gc)(void); + void (*_shutdown)(bool, bool); + + zend_mm_get_custom_handlers_ex(heap, &_malloc, &_free, &_realloc, &_gc, &_shutdown); + zend_mm_set_custom_handlers_ex(heap, NULL, NULL, NULL, NULL, NULL); + + size_t collected = zend_mm_gc(heap); + + zend_mm_set_custom_handlers_ex(heap, _malloc, _free, _realloc, _gc, _shutdown); + + return collected; +} + +static void poison_shutdown(bool full, bool silent) +{ + zend_mm_heap *heap = AG(mm_heap); + + void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); + void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); + void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); + size_t (*_gc)(void); + void (*_shutdown)(bool, bool); + + zend_mm_get_custom_handlers_ex(heap, &_malloc, &_free, &_realloc, &_gc, &_shutdown); + zend_mm_set_custom_handlers_ex(heap, NULL, NULL, NULL, NULL, NULL); + + if (heap->debug.check_freelists_on_shutdown) { + zend_mm_check_freelists(heap); + } + + zend_mm_shutdown(heap, full, silent); + + if (!full) { + zend_mm_set_custom_handlers_ex(heap, _malloc, _free, _realloc, _gc, _shutdown); + } +} + +static void poison_enable(zend_mm_heap *heap, char *parameters) +{ + char *tmp = parameters; + char *end = tmp + strlen(tmp); + + /* Trim heading/trailing whitespaces */ + while (*tmp == ' ' || *tmp == '\t' || *tmp == '\n') { + tmp++; + } + while (end != tmp && (*(end-1) == ' ' || *(end-1) == '\t' || *(end-1) == '\n')) { + end--; + } + + if (tmp == end) { + return; + } + + while (1) { + char *key = tmp; + + tmp = memchr(tmp, '=', end - tmp); + if (!tmp) { + size_t key_len = end - key; + fprintf(stderr, "Unexpected EOF after ZEND_MM_DEBUG parameter '%.*s', expected '='\n", + (int)key_len, key); + return; + } + + size_t key_len = tmp - key; + char *value = tmp + 1; + + if (key_len == strlen("poison_alloc") + && !memcmp(key, "poison_alloc", key_len)) { + + heap->debug.poison_alloc = true; + heap->debug.poison_alloc_value = (uint8_t) ZEND_STRTOUL(value, &tmp, 0); + + } else if (key_len == strlen("poison_free") + && !memcmp(key, "poison_free", key_len)) { + + heap->debug.poison_free = true; + heap->debug.poison_free_value = (uint8_t) ZEND_STRTOUL(value, &tmp, 0); + + } else if (key_len == strlen("padding") + && !memcmp(key, "padding", key_len)) { + + uint8_t padding = ZEND_STRTOUL(value, &tmp, 0); + if (ZEND_MM_ALIGNED_SIZE(padding) != padding) { + fprintf(stderr, "ZEND_MM_DEBUG padding must be a multiple of %u, %u given\n", + (unsigned int)ZEND_MM_ALIGNMENT, + (unsigned int)padding); + return; + } + heap->debug.padding = padding; + + } else if (key_len == strlen("check_freelists_on_shutdown") + && !memcmp(key, "check_freelists_on_shutdown", key_len)) { + + heap->debug.check_freelists_on_shutdown = (bool) ZEND_STRTOUL(value, &tmp, 0); + + } else { + fprintf(stderr, "Unknown ZEND_MM_DEBUG parameter: '%.*s'\n", + (int)key_len, key); + return; + } + + if (tmp == end) { + break; + } + if (*tmp != ',') { + fprintf(stderr, "Unexpected '%c' after value of ZEND_MM_DEBUG parameter '%.*s', expected ','\n", + *tmp, (int)key_len, key); + return; + } + tmp++; + } + + zend_mm_set_custom_handlers_ex(heap, poison_malloc, poison_free, + poison_realloc, poison_gc, poison_shutdown); +} + static void alloc_globals_ctor(zend_alloc_globals *alloc_globals) { char *tmp; @@ -3057,6 +3273,14 @@ static void alloc_globals_ctor(zend_alloc_globals *alloc_globals) zend_mm_use_huge_pages = true; } alloc_globals->mm_heap = zend_mm_init(); + +#if ZEND_MM_CUSTOM + ZEND_ASSERT(!alloc_globals->mm_heap->tracked_allocs); + tmp = getenv("ZEND_MM_DEBUG"); + if (tmp) { + poison_enable(alloc_globals->mm_heap, tmp); + } +#endif } #ifdef ZTS diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 8b0a66fda8096..991d85ff39ce1 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -702,6 +702,41 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner( } zval_ptr_dtor_nogc(&op1); break; + case ZEND_AST_CAST: + if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) { + ret = FAILURE; + break; + } + if (ast->attr == Z_TYPE(op1)) { + ZVAL_COPY_VALUE(result, &op1); + } else { + switch (ast->attr) { + case _IS_BOOL: + ZVAL_BOOL(result, zend_is_true(&op1)); + break; + case IS_LONG: + ZVAL_LONG(result, zval_get_long_func(&op1, false)); + break; + case IS_DOUBLE: + ZVAL_DOUBLE(result, zval_get_double_func(&op1)); + break; + case IS_STRING: + ZVAL_STR(result, zval_get_string_func(&op1)); + break; + case IS_ARRAY: + zend_cast_zval_to_array(result, &op1, IS_VAR); + break; + case IS_OBJECT: + zend_cast_zval_to_object(result, &op1, IS_VAR); + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + zval_ptr_dtor_nogc(&op1); + if (UNEXPECTED(EG(exception))) { + ret = FAILURE; + } + } + break; case ZEND_AST_OR: if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) { ret = FAILURE; @@ -1277,6 +1312,7 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf) new->attr = old->attr; new->lineno = old->lineno; new->op_array = old->op_array; + function_add_ref((zend_function *)new->op_array); buf = (void*)((char*)buf + sizeof(zend_ast_op_array)); } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) { zend_ast_fcc *old = (zend_ast_fcc*)ast; @@ -1353,7 +1389,7 @@ ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast) } else if (EXPECTED(ast->kind == ZEND_AST_CONSTANT)) { zend_string_release_ex(zend_ast_get_constant_name(ast), 0); } else if (EXPECTED(ast->kind == ZEND_AST_OP_ARRAY)) { - /* Nothing to do. */ + destroy_op_array(zend_ast_get_op_array(ast)->op_array); } else if (EXPECTED(zend_ast_is_decl(ast))) { zend_ast_decl *decl = (zend_ast_decl *) ast; @@ -2261,6 +2297,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio EMPTY_SWITCH_DEFAULT_CASE(); } break; + case ZEND_AST_CAST_VOID: + PREFIX_OP("(void)", 240, 241); + break; case ZEND_AST_EMPTY: FUNC_OP("empty"); case ZEND_AST_ISSET: diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index d0dad8490c4e3..9348c35f6cc07 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -84,6 +84,7 @@ enum _zend_ast_kind { ZEND_AST_UNARY_PLUS, ZEND_AST_UNARY_MINUS, ZEND_AST_CAST, + ZEND_AST_CAST_VOID, ZEND_AST_EMPTY, ZEND_AST_ISSET, ZEND_AST_SILENCE, diff --git a/Zend/zend_attributes.c b/Zend/zend_attributes.c index d7bcb1f54e889..48f79c12610f6 100644 --- a/Zend/zend_attributes.c +++ b/Zend/zend_attributes.c @@ -31,6 +31,7 @@ ZEND_API zend_class_entry *zend_ce_sensitive_parameter; ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value; ZEND_API zend_class_entry *zend_ce_override; ZEND_API zend_class_entry *zend_ce_deprecated; +ZEND_API zend_class_entry *zend_ce_nodiscard; static zend_object_handlers attributes_object_handlers_sensitive_parameter_value; @@ -193,6 +194,29 @@ ZEND_METHOD(Deprecated, __construct) } } +ZEND_METHOD(NoDiscard, __construct) +{ + zend_string *message = NULL; + zval value; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_STR_OR_NULL(message) + ZEND_PARSE_PARAMETERS_END(); + + if (message) { + ZVAL_STR(&value, message); + } else { + ZVAL_NULL(&value); + } + zend_update_property_ex(zend_ce_nodiscard, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value); + + /* The assignment might fail due to 'readonly'. */ + if (UNEXPECTED(EG(exception))) { + RETURN_THROWS(); + } +} + static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset) { if (attributes) { @@ -520,6 +544,9 @@ void zend_register_attribute_ce(void) zend_ce_deprecated = register_class_Deprecated(); attr = zend_mark_internal_attribute(zend_ce_deprecated); + + zend_ce_nodiscard = register_class_NoDiscard(); + attr = zend_mark_internal_attribute(zend_ce_nodiscard); } void zend_attributes_shutdown(void) diff --git a/Zend/zend_attributes.h b/Zend/zend_attributes.h index 8a825247c00f8..468488800ebf8 100644 --- a/Zend/zend_attributes.h +++ b/Zend/zend_attributes.h @@ -47,6 +47,7 @@ extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter; extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value; extern ZEND_API zend_class_entry *zend_ce_override; extern ZEND_API zend_class_entry *zend_ce_deprecated; +extern ZEND_API zend_class_entry *zend_ce_nodiscard; typedef struct { zend_string *name; diff --git a/Zend/zend_attributes.stub.php b/Zend/zend_attributes.stub.php index 0a35b0c57cb44..6351ccd771838 100644 --- a/Zend/zend_attributes.stub.php +++ b/Zend/zend_attributes.stub.php @@ -84,3 +84,14 @@ final class Deprecated public function __construct(?string $message = null, ?string $since = null) {} } + +/** + * @strict-properties + */ +#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_FUNCTION)] +final class NoDiscard +{ + public readonly ?string $message; + + public function __construct(?string $message = null) {} +} diff --git a/Zend/zend_attributes_arginfo.h b/Zend/zend_attributes_arginfo.h index 018caa47d0ac5..aecb216291071 100644 --- a/Zend/zend_attributes_arginfo.h +++ b/Zend/zend_attributes_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 2358a0d820edd06a1702c84104bfd545af08311c */ + * Stub hash: 6b54bc195be211caabb395b621380681953c1f5a */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL") @@ -29,6 +29,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Deprecated___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, since, IS_STRING, 1, "null") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_NoDiscard___construct, 0, 0, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 1, "null") +ZEND_END_ARG_INFO() + ZEND_METHOD(Attribute, __construct); ZEND_METHOD(ReturnTypeWillChange, __construct); ZEND_METHOD(AllowDynamicProperties, __construct); @@ -38,6 +42,7 @@ ZEND_METHOD(SensitiveParameterValue, getValue); ZEND_METHOD(SensitiveParameterValue, __debugInfo); ZEND_METHOD(Override, __construct); ZEND_METHOD(Deprecated, __construct); +ZEND_METHOD(NoDiscard, __construct); static const zend_function_entry class_Attribute_methods[] = { ZEND_ME(Attribute, __construct, arginfo_class_Attribute___construct, ZEND_ACC_PUBLIC) @@ -76,6 +81,11 @@ static const zend_function_entry class_Deprecated_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_NoDiscard_methods[] = { + ZEND_ME(NoDiscard, __construct, arginfo_class_NoDiscard___construct, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + static zend_class_entry *register_class_Attribute(void) { zend_class_entry ce, *class_entry; @@ -253,3 +263,24 @@ static zend_class_entry *register_class_Deprecated(void) return class_entry; } + +static zend_class_entry *register_class_NoDiscard(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "NoDiscard", class_NoDiscard_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES); + + zval property_message_default_value; + ZVAL_UNDEF(&property_message_default_value); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_MESSAGE), &property_message_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + + zend_string *attribute_name_Attribute_class_NoDiscard_0 = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, 1); + zend_attribute *attribute_Attribute_class_NoDiscard_0 = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_NoDiscard_0, 1); + zend_string_release(attribute_name_Attribute_class_NoDiscard_0); + zval attribute_Attribute_class_NoDiscard_0_arg0; + ZVAL_LONG(&attribute_Attribute_class_NoDiscard_0_arg0, ZEND_ATTRIBUTE_TARGET_METHOD | ZEND_ATTRIBUTE_TARGET_FUNCTION); + ZVAL_COPY_VALUE(&attribute_Attribute_class_NoDiscard_0->args[0].value, &attribute_Attribute_class_NoDiscard_0_arg0); + + return class_entry; +} diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index bb8bb28bf6e4f..7a07ceadce2e2 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -840,7 +840,7 @@ ZEND_FUNCTION(get_object_vars) } const char *unmangled_name_cstr = zend_get_unmangled_property_name(prop_info->name); zend_string *unmangled_name = zend_string_init(unmangled_name_cstr, strlen(unmangled_name_cstr), false); - zend_read_property_ex(prop_info->ce, zobj, unmangled_name, /* silent */ true, &tmp); + value = zend_read_property_ex(prop_info->ce, zobj, unmangled_name, /* silent */ true, &tmp); zend_string_release_ex(unmangled_name, false); if (EG(exception)) { zend_release_properties(properties); @@ -848,7 +848,6 @@ ZEND_FUNCTION(get_object_vars) ZVAL_UNDEF(return_value); RETURN_THROWS(); } - value = &tmp; } Z_TRY_ADDREF_P(value); @@ -1323,6 +1322,15 @@ ZEND_FUNCTION(restore_error_handler) } /* }}} */ +ZEND_FUNCTION(get_error_handler) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { + RETURN_COPY(&EG(user_error_handler)); + } +} + /* {{{ Sets a user-defined exception handler function. Returns the previously defined exception handler, or false on error */ ZEND_FUNCTION(set_exception_handler) { @@ -1369,6 +1377,15 @@ ZEND_FUNCTION(restore_exception_handler) } /* }}} */ +ZEND_FUNCTION(get_exception_handler) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { + RETURN_COPY(&EG(user_exception_handler)); + } +} + static inline void get_declared_class_impl(INTERNAL_FUNCTION_PARAMETERS, int flags) /* {{{ */ { zend_string *key; diff --git a/Zend/zend_builtin_functions.stub.php b/Zend/zend_builtin_functions.stub.php index f7009c4ffba6e..7f316835aea6b 100644 --- a/Zend/zend_builtin_functions.stub.php +++ b/Zend/zend_builtin_functions.stub.php @@ -117,11 +117,15 @@ function set_error_handler(?callable $callback, int $error_levels = E_ALL) {} function restore_error_handler(): true {} +function get_error_handler(): ?callable {} + /** @return callable|null */ function set_exception_handler(?callable $callback) {} function restore_exception_handler(): true {} +function get_exception_handler(): ?callable {} + /** * @return array * @refcount 1 diff --git a/Zend/zend_builtin_functions_arginfo.h b/Zend/zend_builtin_functions_arginfo.h index cf34b1c0012d5..9498b8292f892 100644 --- a/Zend/zend_builtin_functions_arginfo.h +++ b/Zend/zend_builtin_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 3dbc84896823c9aaa9ac8aeef8841266920c3e50 */ + * Stub hash: a24761186f1ddf758e648b0a764826537cbd33b9 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_exit, 0, 0, IS_NEVER, 0) ZEND_ARG_TYPE_MASK(0, status, MAY_BE_STRING|MAY_BE_LONG, "0") @@ -148,12 +148,17 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_restore_error_handler, 0, 0, IS_TRUE, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_get_error_handler, 0, 0, IS_CALLABLE, 1) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_set_exception_handler, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 1) ZEND_END_ARG_INFO() #define arginfo_restore_exception_handler arginfo_restore_error_handler +#define arginfo_get_exception_handler arginfo_get_error_handler + #define arginfo_get_declared_classes arginfo_func_get_args #define arginfo_get_declared_traits arginfo_func_get_args @@ -272,8 +277,10 @@ ZEND_FUNCTION(get_included_files); ZEND_FUNCTION(trigger_error); ZEND_FUNCTION(set_error_handler); ZEND_FUNCTION(restore_error_handler); +ZEND_FUNCTION(get_error_handler); ZEND_FUNCTION(set_exception_handler); ZEND_FUNCTION(restore_exception_handler); +ZEND_FUNCTION(get_exception_handler); ZEND_FUNCTION(get_declared_classes); ZEND_FUNCTION(get_declared_traits); ZEND_FUNCTION(get_declared_interfaces); @@ -336,8 +343,10 @@ static const zend_function_entry ext_functions[] = { ZEND_RAW_FENTRY("user_error", zif_trigger_error, arginfo_user_error, 0, NULL, NULL) ZEND_FE(set_error_handler, arginfo_set_error_handler) ZEND_FE(restore_error_handler, arginfo_restore_error_handler) + ZEND_FE(get_error_handler, arginfo_get_error_handler) ZEND_FE(set_exception_handler, arginfo_set_exception_handler) ZEND_FE(restore_exception_handler, arginfo_restore_exception_handler) + ZEND_FE(get_exception_handler, arginfo_get_exception_handler) ZEND_FE(get_declared_classes, arginfo_get_declared_classes) ZEND_FE(get_declared_traits, arginfo_get_declared_traits) ZEND_FE(get_declared_interfaces, arginfo_get_declared_interfaces) diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index e9945b3284cd9..5777e1a34a2b8 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -528,7 +528,6 @@ static void zend_closure_free_storage(zend_object *object) /* {{{ */ /* We don't own the static variables of fake closures. */ if (!(closure->func.op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE)) { zend_destroy_static_vars(&closure->func.op_array); - closure->func.op_array.static_variables = NULL; } destroy_op_array(&closure->func.op_array); } else if (closure->func.type == ZEND_INTERNAL_FUNCTION) { @@ -760,16 +759,14 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en } /* For fake closures, we want to reuse the static variables of the original function. */ + HashTable *ht = ZEND_MAP_PTR_GET(func->op_array.static_variables_ptr); if (!is_fake) { - if (closure->func.op_array.static_variables) { - closure->func.op_array.static_variables = - zend_array_dup(closure->func.op_array.static_variables); + if (!ht) { + ht = closure->func.op_array.static_variables; } ZEND_MAP_PTR_INIT(closure->func.op_array.static_variables_ptr, - closure->func.op_array.static_variables); + ht ? zend_array_dup(ht) : NULL); } else if (func->op_array.static_variables) { - HashTable *ht = ZEND_MAP_PTR_GET(func->op_array.static_variables_ptr); - if (!ht) { ht = zend_array_dup(func->op_array.static_variables); ZEND_MAP_PTR_SET(func->op_array.static_variables_ptr, ht); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index e5df485919942..5c15832f80a89 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1407,10 +1407,10 @@ static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scop } static zend_string *add_intersection_type(zend_string *str, - zend_type_list *intersection_type_list, zend_class_entry *scope, + const zend_type_list *intersection_type_list, zend_class_entry *scope, bool is_bracketed) { - zend_type *single_type; + const zend_type *single_type; zend_string *intersection_str = NULL; ZEND_TYPE_LIST_FOREACH(intersection_type_list, single_type) { @@ -1432,7 +1432,7 @@ static zend_string *add_intersection_type(zend_string *str, return str; } -zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope) { +zend_string *zend_type_to_string_resolved(const zend_type type, zend_class_entry *scope) { zend_string *str = NULL; /* Pure intersection type */ @@ -1441,7 +1441,7 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop str = add_intersection_type(str, ZEND_TYPE_LIST(type), scope, /* is_bracketed */ false); } else if (ZEND_TYPE_HAS_LIST(type)) { /* A union type might not be a list */ - zend_type *list_type; + const zend_type *list_type; ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) { if (ZEND_TYPE_IS_INTERSECTION(*list_type)) { str = add_intersection_type(str, ZEND_TYPE_LIST(*list_type), scope, /* is_bracketed */ true); @@ -1527,7 +1527,7 @@ ZEND_API zend_string *zend_type_to_string(zend_type type) { return zend_type_to_string_resolved(type, NULL); } -static bool is_generator_compatible_class_type(zend_string *name) { +static bool is_generator_compatible_class_type(const zend_string *name) { return zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_TRAVERSABLE)) || zend_string_equals_literal_ci(name, "Iterator") || zend_string_equals_literal_ci(name, "Generator"); @@ -1541,10 +1541,10 @@ static void zend_mark_function_as_generator(void) /* {{{ */ } if (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { - zend_type return_type = CG(active_op_array)->arg_info[-1].type; + const zend_type return_type = CG(active_op_array)->arg_info[-1].type; bool valid_type = (ZEND_TYPE_FULL_MASK(return_type) & MAY_BE_OBJECT) != 0; if (!valid_type) { - zend_type *single_type; + const zend_type *single_type; ZEND_TYPE_FOREACH(return_type, single_type) { if (ZEND_TYPE_HAS_NAME(*single_type) && is_generator_compatible_class_type(ZEND_TYPE_NAME(*single_type))) { @@ -2620,33 +2620,6 @@ static void zend_compile_memoized_expr(znode *result, zend_ast *expr) /* {{{ */ } /* }}} */ -/* Remember to update type_num_classes() in compact_literals.c when changing this function */ -static size_t zend_type_get_num_classes(zend_type type) { - if (!ZEND_TYPE_IS_COMPLEX(type)) { - return 0; - } - if (ZEND_TYPE_HAS_LIST(type)) { - /* Intersection types cannot have nested list types */ - if (ZEND_TYPE_IS_INTERSECTION(type)) { - return ZEND_TYPE_LIST(type)->num_types; - } - ZEND_ASSERT(ZEND_TYPE_IS_UNION(type)); - size_t count = 0; - zend_type *list_type; - - ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) { - if (ZEND_TYPE_IS_INTERSECTION(*list_type)) { - count += ZEND_TYPE_LIST(*list_type)->num_types; - } else { - ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type)); - count += 1; - } - } ZEND_TYPE_LIST_FOREACH_END(); - return count; - } - return 1; -} - static void zend_emit_return_type_check( znode *expr, zend_arg_info *return_info, bool implicit) /* {{{ */ { @@ -2708,8 +2681,6 @@ static void zend_emit_return_type_check( opline->result_type = expr->op_type = IS_TMP_VAR; opline->result.var = expr->u.op.var = get_temporary_variable(); } - - opline->op2.num = zend_alloc_cache_slots(zend_type_get_num_classes(return_info->type)); } } /* }}} */ @@ -3927,13 +3898,15 @@ static uint32_t zend_compile_args( } /* }}} */ -ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc) /* {{{ */ +ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc, bool result_used) /* {{{ */ { - if (fbc) { + uint32_t no_discard = result_used ? 0 : ZEND_ACC_NODISCARD; + + if (fbc && init_op->opcode != ZEND_NEW) { ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)); if (fbc->type == ZEND_INTERNAL_FUNCTION && !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS)) { if (init_op->opcode == ZEND_INIT_FCALL && !zend_execute_internal) { - if (!(fbc->common.fn_flags & ZEND_ACC_DEPRECATED)) { + if (!(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) { return ZEND_DO_ICALL; } else { return ZEND_DO_FCALL_BY_NAME; @@ -3941,7 +3914,7 @@ ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc) /* } } else if (!(CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)){ if (zend_execute_ex == execute_ex) { - if (!(fbc->common.fn_flags & ZEND_ACC_DEPRECATED)) { + if (!(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) { return ZEND_DO_UCALL; } else { return ZEND_DO_FCALL_BY_NAME; @@ -3991,7 +3964,16 @@ static bool zend_compile_call_common(znode *result, zend_ast *args_ast, zend_fun opline->op1.num = zend_vm_calc_used_stack(arg_count, fbc); } - opline = zend_emit_op(result, zend_get_call_op(opline, fbc), NULL, NULL); + uint8_t call_op = zend_get_call_op( + opline, + fbc, + /* result_used: At this point we do not yet reliably + * know if the result is used. Deoptimize #[\NoDiscard] + * calls to be sure. The optimizer will fix this up. + */ + false + ); + opline = zend_emit_op(result, call_op, NULL, NULL); if (may_have_extra_named_args) { opline->extended_value = ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS; } @@ -5735,6 +5717,26 @@ static void zend_compile_return(zend_ast *ast) /* {{{ */ } /* }}} */ +static void zend_compile_void_cast(znode *result, zend_ast *ast) +{ + zend_ast *expr_ast = ast->child[0]; + znode expr_node; + zend_op *opline; + + zend_compile_expr(&expr_node, expr_ast); + + switch (expr_node.op_type) { + case IS_TMP_VAR: + case IS_VAR: + opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL); + opline->extended_value = ZEND_FREE_VOID_CAST; + break; + case IS_CONST: + zend_do_free(&expr_node); + break; + } +} + static void zend_compile_echo(zend_ast *ast) /* {{{ */ { zend_op *opline; @@ -5985,7 +5987,7 @@ static void zend_compile_do_while(zend_ast *ast) /* {{{ */ } /* }}} */ -static void zend_compile_expr_list(znode *result, zend_ast *ast) /* {{{ */ +static void zend_compile_for_expr_list(znode *result, zend_ast *ast) /* {{{ */ { zend_ast_list *list; uint32_t i; @@ -6002,7 +6004,13 @@ static void zend_compile_expr_list(znode *result, zend_ast *ast) /* {{{ */ zend_ast *expr_ast = list->child[i]; zend_do_free(result); - zend_compile_expr(result, expr_ast); + if (expr_ast->kind == ZEND_AST_CAST_VOID) { + zend_compile_void_cast(NULL, expr_ast); + result->op_type = IS_CONST; + ZVAL_NULL(&result->u.constant); + } else { + zend_compile_expr(result, expr_ast); + } } } /* }}} */ @@ -6017,7 +6025,7 @@ static void zend_compile_for(zend_ast *ast) /* {{{ */ znode result; uint32_t opnum_start, opnum_jmp, opnum_loop; - zend_compile_expr_list(&result, init_ast); + zend_compile_for_expr_list(&result, init_ast); zend_do_free(&result); opnum_jmp = zend_emit_jump(0); @@ -6028,11 +6036,11 @@ static void zend_compile_for(zend_ast *ast) /* {{{ */ zend_compile_stmt(stmt_ast); opnum_loop = get_next_op_number(); - zend_compile_expr_list(&result, loop_ast); + zend_compile_for_expr_list(&result, loop_ast); zend_do_free(&result); zend_update_jump_target_to_next(opnum_jmp); - zend_compile_expr_list(&result, cond_ast); + zend_compile_for_expr_list(&result, cond_ast); zend_do_extended_stmt(); zend_emit_cond_jump(ZEND_JMPNZ, &result, opnum_start); @@ -7037,7 +7045,7 @@ static zend_type zend_compile_single_typename(zend_ast *ast) } } -static void zend_are_intersection_types_redundant(zend_type left_type, zend_type right_type) +static void zend_are_intersection_types_redundant(const zend_type left_type, const zend_type right_type) { ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(left_type)); ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(right_type)); @@ -7056,9 +7064,9 @@ static void zend_are_intersection_types_redundant(zend_type left_type, zend_type } unsigned int sum = 0; - zend_type *outer_type; + const zend_type *outer_type; ZEND_TYPE_LIST_FOREACH(smaller_type_list, outer_type) - zend_type *inner_type; + const zend_type *inner_type; ZEND_TYPE_LIST_FOREACH(larger_type_list, inner_type) if (zend_string_equals_ci(ZEND_TYPE_NAME(*inner_type), ZEND_TYPE_NAME(*outer_type))) { sum++; @@ -7087,12 +7095,12 @@ static void zend_are_intersection_types_redundant(zend_type left_type, zend_type } } -static void zend_is_intersection_type_redundant_by_single_type(zend_type intersection_type, zend_type single_type) +static void zend_is_intersection_type_redundant_by_single_type(const zend_type intersection_type, const zend_type single_type) { ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(intersection_type)); ZEND_ASSERT(!ZEND_TYPE_IS_INTERSECTION(single_type)); - zend_type *single_intersection_type = NULL; + const zend_type *single_intersection_type = NULL; ZEND_TYPE_FOREACH(intersection_type, single_intersection_type) if (zend_string_equals_ci(ZEND_TYPE_NAME(*single_intersection_type), ZEND_TYPE_NAME(single_type))) { zend_string *single_type_str = zend_type_to_string(single_type); @@ -7104,7 +7112,7 @@ static void zend_is_intersection_type_redundant_by_single_type(zend_type interse } /* Used by both intersection and union types prior to transforming the type list to a full zend_type */ -static void zend_is_type_list_redundant_by_single_type(zend_type_list *type_list, zend_type type) +static void zend_is_type_list_redundant_by_single_type(const zend_type_list *type_list, const zend_type type) { ZEND_ASSERT(!ZEND_TYPE_IS_INTERSECTION(type)); for (size_t i = 0; i < type_list->num_types - 1; i++) { @@ -7743,12 +7751,6 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 SET_NODE(opline->result, &var_node); opline->op1.num = i + 1; - if (type_ast) { - /* Allocate cache slot to speed-up run-time class resolution */ - opline->extended_value = - zend_alloc_cache_slots(zend_type_get_num_classes(arg_info->type)); - } - uint32_t arg_info_flags = _ZEND_ARG_INFO_FLAGS(is_ref, is_variadic, /* is_tentative */ 0) | (is_promoted ? _ZEND_IS_PROMOTED_BIT : 0); ZEND_TYPE_FULL_MASK(arg_info->type) |= arg_info_flags; @@ -8244,9 +8246,6 @@ static zend_string *zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_register_seen_symbol(lcname, ZEND_SYMBOL_FUNCTION); switch (level) { - case FUNC_DECL_LEVEL_CONSTEXPR: - zend_add_dynamic_func_def(op_array); - break; case FUNC_DECL_LEVEL_NESTED: { uint32_t func_ref = zend_add_dynamic_func_def(op_array); if (op_array->fn_flags & ZEND_ACC_CLOSURE) { @@ -8261,6 +8260,7 @@ static zend_string *zend_begin_func_decl(znode *result, zend_op_array *op_array, } break; } + case FUNC_DECL_LEVEL_CONSTEXPR: case FUNC_DECL_LEVEL_TOPLEVEL: /* Nothing to do. */ break; @@ -8355,6 +8355,16 @@ static zend_op_array *zend_compile_func_decl_ex( if (deprecated_attribute) { op_array->fn_flags |= ZEND_ACC_DEPRECATED; } + + zend_attribute *nodiscard_attribute = zend_get_attribute_str( + op_array->attributes, + "nodiscard", + sizeof("nodiscard")-1 + ); + + if (nodiscard_attribute) { + op_array->fn_flags |= ZEND_ACC_NODISCARD; + } } /* Do not leak the class scope into free standing functions, even if they are dynamically @@ -8405,6 +8415,27 @@ static zend_op_array *zend_compile_func_decl_ex( } } + if (op_array->fn_flags & ZEND_ACC_NODISCARD) { + if (is_hook) { + zend_error_noreturn(E_COMPILE_ERROR, "#[\\NoDiscard] is not supported for property hooks"); + } + + if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { + zend_arg_info *return_info = CG(active_op_array)->arg_info - 1; + if (ZEND_TYPE_CONTAINS_CODE(return_info->type, IS_VOID)) { + zend_error_noreturn(E_COMPILE_ERROR, + "A void %s does not return a value, but #[\\NoDiscard] requires a return value", + CG(active_class_entry) != NULL ? "method" : "function"); + } + + if (ZEND_TYPE_CONTAINS_CODE(return_info->type, IS_NEVER)) { + zend_error_noreturn(E_COMPILE_ERROR, + "A never returning %s does not return a value, but #[\\NoDiscard] requires a return value", + CG(active_class_entry) != NULL ? "method" : "function"); + } + } + } + zend_compile_stmt(stmt_ast); if (is_method) { @@ -8654,10 +8685,6 @@ static void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t f zend_error_noreturn(E_COMPILE_ERROR, "Property cannot be both final and private"); } - if ((flags & ZEND_ACC_STATIC) && (flags & ZEND_ACC_PPP_SET_MASK)) { - zend_error_noreturn(E_COMPILE_ERROR, "Static property may not have asymmetric visibility"); - } - if (ce->ce_flags & ZEND_ACC_INTERFACE) { if (flags & ZEND_ACC_FINAL) { zend_error_noreturn(E_COMPILE_ERROR, "Property in interface cannot be final"); @@ -8686,7 +8713,7 @@ static void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t f zend_type type = ZEND_TYPE_INIT_NONE(0); flags |= zend_property_is_virtual(ce, name, hooks_ast, flags) ? ZEND_ACC_VIRTUAL : 0; - ZEND_ASSERT(!CG(context).active_property_info_name); + zend_string *old_active_property_info_name = CG(context).active_property_info_name; CG(context).active_property_info_name = name; if (!hooks_ast) { @@ -8782,7 +8809,7 @@ static void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t f zend_compile_attributes(&info->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY, 0); } - CG(context).active_property_info_name = NULL; + CG(context).active_property_info_name = old_active_property_info_name; } } /* }}} */ @@ -8862,6 +8889,10 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as if (deprecated) { ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_DEPRECATED; + /* For deprecated constants, we need to flag the zval for recursion + * detection. Make sure the zval is separated out of shm. */ + ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS; + ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; } } } @@ -11096,6 +11127,7 @@ static bool zend_is_allowed_in_const_expr(zend_ast_kind kind) /* {{{ */ || kind == ZEND_AST_AND || kind == ZEND_AST_OR || kind == ZEND_AST_UNARY_OP || kind == ZEND_AST_UNARY_PLUS || kind == ZEND_AST_UNARY_MINUS + || kind == ZEND_AST_CAST || kind == ZEND_AST_CONDITIONAL || kind == ZEND_AST_DIM || kind == ZEND_AST_ARRAY || kind == ZEND_AST_ARRAY_ELEM || kind == ZEND_AST_UNPACK @@ -11370,6 +11402,12 @@ static void zend_compile_const_expr(zend_ast **ast_ptr, void *context) /* {{{ */ case ZEND_AST_MAGIC_CONST: zend_compile_const_expr_magic_const(ast_ptr); break; + case ZEND_AST_CAST: + if (ast->attr == IS_OBJECT && !ctx->allow_dynamic) { + zend_error_noreturn(E_COMPILE_ERROR, + "Object casts are not supported in this context"); + } + break; case ZEND_AST_NEW: if (!ctx->allow_dynamic) { zend_error_noreturn(E_COMPILE_ERROR, @@ -11547,6 +11585,9 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */ case ZEND_AST_THROW: zend_compile_expr(NULL, ast); break; + case ZEND_AST_CAST_VOID: + zend_compile_void_cast(NULL, ast); + break; default: { znode result; @@ -12086,6 +12127,9 @@ static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ zend_eval_const_expr(&ast->child[0]); zend_eval_const_expr(&ast->child[1]); return; + case ZEND_AST_CAST: + zend_eval_const_expr(&ast->child[0]); + return; default: return; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index a7ee8f9327c54..4f7d158ba0f1c 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -333,7 +333,7 @@ typedef struct _zend_oparray_context { /* Class cannot be serialized or unserialized | | | */ #define ZEND_ACC_NOT_SERIALIZABLE (1 << 29) /* X | | | */ /* | | | */ -/* Function Flags (unused: 29-30) | | | */ +/* Function Flags (unused: 30) | | | */ /* ============== | | | */ /* | | | */ /* deprecation flag | | | */ @@ -395,6 +395,9 @@ typedef struct _zend_oparray_context { /* has #[\Override] attribute | | | */ #define ZEND_ACC_OVERRIDE (1 << 28) /* | X | | */ /* | | | */ +/* has #[\NoDiscard] attribute | | | */ +#define ZEND_ACC_NODISCARD (1 << 29) /* | X | | */ +/* | | | */ /* op_array uses strict mode types | | | */ #define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */ @@ -464,6 +467,8 @@ typedef struct _zend_property_info { ((uint32_t)(XtOffsetOf(zend_object, properties_table) + sizeof(zval) * (num))) #define OBJ_PROP_TO_NUM(offset) \ (((offset) - OBJ_PROP_TO_OFFSET(0)) / sizeof(zval)) +#define OBJ_PROP_SLOT_TO_OFFSET(obj, slot) \ + ((uintptr_t)(slot) - (uintptr_t)(obj)) typedef struct _zend_class_constant { zval value; /* flags are stored in u2 */ @@ -981,7 +986,7 @@ ZEND_API bool zend_is_compiling(void); ZEND_API char *zend_make_compiled_string_description(const char *name); ZEND_API void zend_initialize_class_data(zend_class_entry *ce, bool nullify_handlers); uint32_t zend_get_class_fetch_type(const zend_string *name); -ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc); +ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc, bool result_used); ZEND_API bool zend_is_smart_branch(const zend_op *opline); typedef bool (*zend_auto_global_callback)(zend_string *name); @@ -1092,6 +1097,7 @@ ZEND_API zend_string *zend_type_to_string(zend_type type); #define ZEND_FREE_ON_RETURN (1<<0) #define ZEND_FREE_SWITCH (1<<1) +#define ZEND_FREE_VOID_CAST (1<<2) #define ZEND_SEND_BY_VAL 0u #define ZEND_SEND_BY_REF 1u diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index c95f6f4289f69..f29466cfe2c9c 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -362,8 +362,10 @@ ZEND_API zval *zend_get_class_constant_ex(zend_string *class_name, zend_string * } if (UNEXPECTED(ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED)) { - if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) { + if ((flags & ZEND_FETCH_CLASS_SILENT) == 0 && !CONST_IS_RECURSIVE(c)) { + CONST_PROTECT_RECURSION(c); zend_deprecated_class_constant(c, constant_name); + CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { goto failure; } diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h index fbefe0011ae1e..4a4da46bfc9b1 100644 --- a/Zend/zend_constants.h +++ b/Zend/zend_constants.h @@ -27,6 +27,17 @@ #define CONST_NO_FILE_CACHE (1<<1) /* Can't be saved in file cache */ #define CONST_DEPRECATED (1<<2) /* Deprecated */ #define CONST_OWNED (1<<3) /* constant should be destroyed together with class */ +#define CONST_RECURSIVE (1<<4) /* Recursion protection for constant evaluation */ + +#define CONST_IS_RECURSIVE(c) (Z_CONSTANT_FLAGS((c)->value) & CONST_RECURSIVE) +#define CONST_PROTECT_RECURSION(c) \ + do { \ + Z_CONSTANT_FLAGS((c)->value) |= CONST_RECURSIVE; \ + } while (0) +#define CONST_UNPROTECT_RECURSION(c) \ + do { \ + Z_CONSTANT_FLAGS((c)->value) &= ~CONST_RECURSIVE; \ + } while (0) #define PHP_USER_CONSTANT 0x7fffff /* a constant defined in user space */ diff --git a/Zend/zend_enum.c b/Zend/zend_enum.c index ccafca48fe9b8..6baa34cc50125 100644 --- a/Zend/zend_enum.c +++ b/Zend/zend_enum.c @@ -610,8 +610,7 @@ ZEND_API void zend_enum_add_case_cstr(zend_class_entry *ce, const char *name, zv zend_string_release(name_str); } -ZEND_API zend_object *zend_enum_get_case(zend_class_entry *ce, zend_string *name) { - zend_class_constant *c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name); +static zend_object *zend_enum_case_from_class_constant(zend_class_constant *c) { ZEND_ASSERT(c && "Must be a valid enum case"); ZEND_ASSERT(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE); @@ -624,9 +623,12 @@ ZEND_API zend_object *zend_enum_get_case(zend_class_entry *ce, zend_string *name return Z_OBJ(c->value); } +ZEND_API zend_object *zend_enum_get_case(zend_class_entry *ce, zend_string *name) { + zend_class_constant *c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name); + return zend_enum_case_from_class_constant(c); +} + ZEND_API zend_object *zend_enum_get_case_cstr(zend_class_entry *ce, const char *name) { - zend_string *name_str = zend_string_init(name, strlen(name), 0); - zend_object *result = zend_enum_get_case(ce, name_str); - zend_string_release(name_str); - return result; + zend_class_constant *c = zend_hash_str_find_ptr(CE_CONSTANTS_TABLE(ce), name, strlen(name)); + return zend_enum_case_from_class_constant(c); } diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 6b6af2c225f79..89fbcf2cbd781 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -609,7 +609,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference(uint32_t arg zend_string_release(func_name); } -static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_prop_error(zend_property_info *prop) { +static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_prop_error(const zend_property_info *prop) { zend_string *type_str = zend_type_to_string(prop->type); zend_type_error( "Cannot auto-initialize an array inside property %s::$%s of type %s", @@ -619,7 +619,7 @@ static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_prop_error(zend_ zend_string_release(type_str); } -static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_ref_error(zend_property_info *prop) { +static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_ref_error(const zend_property_info *prop) { zend_string *type_str = zend_type_to_string(prop->type); zend_type_error( "Cannot auto-initialize an array inside a reference held by property %s::$%s of type %s", @@ -630,7 +630,7 @@ static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_ref_error(zend_p } static zend_never_inline ZEND_COLD void zend_throw_access_uninit_prop_by_ref_error( - zend_property_info *prop) { + const zend_property_info *prop) { zend_throw_error(NULL, "Cannot access uninitialized non-nullable property %s::$%s by reference", ZSTR_VAL(prop->ce->name), @@ -638,7 +638,7 @@ static zend_never_inline ZEND_COLD void zend_throw_access_uninit_prop_by_ref_err } /* this should modify object only if it's empty */ -static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_throw_non_object_error(zval *object, zval *property OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_throw_non_object_error(const zval *object, zval *property OPLINE_DC EXECUTE_DATA_DC) { zend_string *tmp_property_name; zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name); @@ -673,7 +673,7 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_throw_non_object_erro } static ZEND_COLD void zend_verify_type_error_common( - const zend_function *zf, const zend_arg_info *arg_info, zval *value, + const zend_function *zf, const zend_arg_info *arg_info, const zval *value, const char **fname, const char **fsep, const char **fclass, zend_string **need_msg, const char **given_kind) { @@ -696,9 +696,9 @@ static ZEND_COLD void zend_verify_type_error_common( } ZEND_API ZEND_COLD void zend_verify_arg_error( - const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, zval *value) + const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, const zval *value) { - zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data; + const zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data; const char *fname, *fsep, *fclass; zend_string *need_msg; const char *given_msg; @@ -909,7 +909,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modificati ZSTR_VAL(info->ce->name), zend_get_unmangled_property_name(info->name)); } -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_invalid_class_constant_type_error(uint8_t type) +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_invalid_class_constant_type_error(const uint8_t type) { zend_type_error("Cannot use value of type %s as class constant name", zend_get_type_by_const(type)); } @@ -975,9 +975,9 @@ static zend_always_inline const zend_class_entry *zend_ce_from_type( } static bool zend_check_intersection_for_property_or_class_constant_class_type( - const zend_class_entry *scope, zend_type_list *intersection_type_list, const zend_class_entry *value_ce) + const zend_class_entry *scope, const zend_type_list *intersection_type_list, const zend_class_entry *value_ce) { - zend_type *list_type; + const zend_type *list_type; ZEND_TYPE_LIST_FOREACH(intersection_type_list, list_type) { ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type)); @@ -990,13 +990,13 @@ static bool zend_check_intersection_for_property_or_class_constant_class_type( } static bool zend_check_and_resolve_property_or_class_constant_class_type( - const zend_class_entry *scope, zend_type member_type, const zend_class_entry *value_ce) { + const zend_class_entry *scope, const zend_type member_type, const zend_class_entry *value_ce) { if (ZEND_TYPE_HAS_LIST(member_type)) { - zend_type *list_type; if (ZEND_TYPE_IS_INTERSECTION(member_type)) { return zend_check_intersection_for_property_or_class_constant_class_type( scope, ZEND_TYPE_LIST(member_type), value_ce); } else { + const zend_type *list_type; ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(member_type), list_type) { if (ZEND_TYPE_IS_INTERSECTION(*list_type)) { if (zend_check_intersection_for_property_or_class_constant_class_type( @@ -1059,7 +1059,7 @@ ZEND_API bool zend_never_inline zend_verify_property_type(const zend_property_in return i_zend_verify_property_type(info, property, strict); } -static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *info, zval *property_val, zval *value, zend_refcounted **garbage_ptr EXECUTE_DATA_DC) +static zend_never_inline zval* zend_assign_to_typed_prop(const zend_property_info *info, zval *property_val, zval *value, zend_refcounted **garbage_ptr EXECUTE_DATA_DC) { zval tmp; @@ -1087,7 +1087,7 @@ static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *inf return zend_assign_to_variable_ex(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES(), garbage_ptr); } -static zend_always_inline bool zend_value_instanceof_static(zval *zv) { +static zend_always_inline bool zend_value_instanceof_static(const zval *zv) { if (Z_TYPE_P(zv) != IS_OBJECT) { return 0; } @@ -1099,23 +1099,9 @@ static zend_always_inline bool zend_value_instanceof_static(zval *zv) { return instanceof_function(Z_OBJCE_P(zv), called_scope); } -/* The cache_slot may only be NULL in debug builds, where arginfo verification of - * internal functions is enabled. Avoid unnecessary checks in release builds. */ -#if ZEND_DEBUG -# define HAVE_CACHE_SLOT (cache_slot != NULL) -#else -# define HAVE_CACHE_SLOT 1 -#endif - -#define PROGRESS_CACHE_SLOT() if (HAVE_CACHE_SLOT) {cache_slot++;} - -static zend_always_inline zend_class_entry *zend_fetch_ce_from_cache_slot( - void **cache_slot, zend_type *type) +static zend_always_inline zend_class_entry *zend_fetch_ce_from_type( + const zend_type *type) { - if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) { - return (zend_class_entry *) *cache_slot; - } - zend_string *name = ZEND_TYPE_NAME(*type); zend_class_entry *ce; if (ZSTR_HAS_CE_CACHE(name)) { @@ -1134,68 +1120,54 @@ static zend_always_inline zend_class_entry *zend_fetch_ce_from_cache_slot( return NULL; } } - if (HAVE_CACHE_SLOT) { - *cache_slot = (void *) ce; - } return ce; } -static bool zend_check_intersection_type_from_cache_slot(zend_type_list *intersection_type_list, - zend_class_entry *arg_ce, void ***cache_slot_ptr) +static bool zend_check_intersection_type_from_list( + const zend_type_list *intersection_type_list, + zend_class_entry *arg_ce) { - void **cache_slot = *cache_slot_ptr; zend_class_entry *ce; - zend_type *list_type; - bool status = true; + const zend_type *list_type; ZEND_TYPE_LIST_FOREACH(intersection_type_list, list_type) { - /* Only check classes if the type might be valid */ - if (status) { - ce = zend_fetch_ce_from_cache_slot(cache_slot, list_type); - /* If type is not an instance of one of the types taking part in the - * intersection it cannot be a valid instance of the whole intersection type. */ - if (!ce || !instanceof_function(arg_ce, ce)) { - status = false; - } + ce = zend_fetch_ce_from_type(list_type); + /* If type is not an instance of one of the types taking part in the + * intersection it cannot be a valid instance of the whole intersection type. */ + if (!ce || !instanceof_function(arg_ce, ce)) { + return false; } - PROGRESS_CACHE_SLOT(); } ZEND_TYPE_LIST_FOREACH_END(); - if (HAVE_CACHE_SLOT) { - *cache_slot_ptr = cache_slot; - } - return status; + return true; } static zend_always_inline bool zend_check_type_slow( - zend_type *type, zval *arg, zend_reference *ref, void **cache_slot, + const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type, bool is_internal) { - uint32_t type_mask; if (ZEND_TYPE_IS_COMPLEX(*type) && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { zend_class_entry *ce; if (UNEXPECTED(ZEND_TYPE_HAS_LIST(*type))) { - zend_type *list_type; if (ZEND_TYPE_IS_INTERSECTION(*type)) { - return zend_check_intersection_type_from_cache_slot(ZEND_TYPE_LIST(*type), Z_OBJCE_P(arg), &cache_slot); + return zend_check_intersection_type_from_list(ZEND_TYPE_LIST(*type), Z_OBJCE_P(arg)); } else { + const zend_type *list_type; ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*type), list_type) { if (ZEND_TYPE_IS_INTERSECTION(*list_type)) { - if (zend_check_intersection_type_from_cache_slot(ZEND_TYPE_LIST(*list_type), Z_OBJCE_P(arg), &cache_slot)) { + if (zend_check_intersection_type_from_list(ZEND_TYPE_LIST(*list_type), Z_OBJCE_P(arg))) { return true; } - /* The cache_slot is progressed in zend_check_intersection_type_from_cache_slot() */ } else { ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type)); - ce = zend_fetch_ce_from_cache_slot(cache_slot, list_type); + ce = zend_fetch_ce_from_type(list_type); /* Instance of a single type part of a union is sufficient to pass the type check */ if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) { return true; } - PROGRESS_CACHE_SLOT(); } } ZEND_TYPE_LIST_FOREACH_END(); } } else { - ce = zend_fetch_ce_from_cache_slot(cache_slot, type); + ce = zend_fetch_ce_from_type(type); /* If we have a CE we check if it satisfies the type constraint, * otherwise it will check if a standard type satisfies it. */ if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) { @@ -1204,7 +1176,7 @@ static zend_always_inline bool zend_check_type_slow( } } - type_mask = ZEND_TYPE_FULL_MASK(*type); + const uint32_t type_mask = ZEND_TYPE_FULL_MASK(*type); if ((type_mask & MAY_BE_CALLABLE) && zend_is_callable(arg, is_internal ? IS_CALLABLE_SUPPRESS_DEPRECATIONS : 0, NULL)) { return 1; @@ -1232,10 +1204,10 @@ static zend_always_inline bool zend_check_type_slow( } static zend_always_inline bool zend_check_type( - zend_type *type, zval *arg, void **cache_slot, zend_class_entry *scope, + const zend_type *type, zval *arg, zend_class_entry *scope, bool is_return_type, bool is_internal) { - zend_reference *ref = NULL; + const zend_reference *ref = NULL; ZEND_ASSERT(ZEND_TYPE_IS_SET(*type)); if (UNEXPECTED(Z_ISREF_P(arg))) { @@ -1247,25 +1219,25 @@ static zend_always_inline bool zend_check_type( return 1; } - return zend_check_type_slow(type, arg, ref, cache_slot, is_return_type, is_internal); + return zend_check_type_slow(type, arg, ref, is_return_type, is_internal); } ZEND_API bool zend_check_user_type_slow( - zend_type *type, zval *arg, zend_reference *ref, void **cache_slot, bool is_return_type) + const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type) { return zend_check_type_slow( - type, arg, ref, cache_slot, is_return_type, /* is_internal */ false); + type, arg, ref, is_return_type, /* is_internal */ false); } -static zend_always_inline bool zend_verify_recv_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, void **cache_slot) +static zend_always_inline bool zend_verify_recv_arg_type(const zend_function *zf, uint32_t arg_num, zval *arg) { - zend_arg_info *cur_arg_info; + const zend_arg_info *cur_arg_info; ZEND_ASSERT(arg_num <= zf->common.num_args); cur_arg_info = &zf->common.arg_info[arg_num-1]; if (ZEND_TYPE_IS_SET(cur_arg_info->type) - && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, cache_slot, zf->common.scope, 0, 0))) { + && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, zf->common.scope, 0, 0))) { zend_verify_arg_error(zf, cur_arg_info, arg_num, arg); return 0; } @@ -1274,10 +1246,10 @@ static zend_always_inline bool zend_verify_recv_arg_type(zend_function *zf, uint } static zend_always_inline bool zend_verify_variadic_arg_type( - zend_function *zf, zend_arg_info *arg_info, uint32_t arg_num, zval *arg, void **cache_slot) + const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, zval *arg) { ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type)); - if (UNEXPECTED(!zend_check_type(&arg_info->type, arg, cache_slot, zf->common.scope, 0, 0))) { + if (UNEXPECTED(!zend_check_type(&arg_info->type, arg, zf->common.scope, 0, 0))) { zend_verify_arg_error(zf, arg_info, arg_num, arg); return 0; } @@ -1285,7 +1257,7 @@ static zend_always_inline bool zend_verify_variadic_arg_type( return 1; } -static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_types(zend_function *fbc, zend_execute_data *call) +static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_types(const zend_function *fbc, zend_execute_data *call) { uint32_t i; uint32_t num_args = ZEND_CALL_NUM_ARGS(call); @@ -1302,7 +1274,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ } if (ZEND_TYPE_IS_SET(cur_arg_info->type) - && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, /* cache_slot */ NULL, fbc->common.scope, 0, /* is_internal */ 1))) { + && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, fbc->common.scope, 0, /* is_internal */ 1))) { return 0; } arg++; @@ -1314,7 +1286,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ /* Determine whether an internal call should throw, because the passed arguments violate * an arginfo constraint. This is only checked in debug builds. In release builds, we * trust that arginfo matches what is enforced by zend_parse_parameters. */ -ZEND_API bool zend_internal_call_should_throw(zend_function *fbc, zend_execute_data *call) +ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_execute_data *call) { if (fbc->internal_function.handler == ZEND_FN(pass) || (fbc->internal_function.fn_flags & ZEND_ACC_FAKE_CLOSURE)) { /* Be lenient about the special pass function and about fake closures. */ @@ -1341,7 +1313,7 @@ ZEND_API bool zend_internal_call_should_throw(zend_function *fbc, zend_execute_d return 0; } -ZEND_API ZEND_COLD void zend_internal_call_arginfo_violation(zend_function *fbc) +ZEND_API ZEND_COLD void zend_internal_call_arginfo_violation(const zend_function *fbc) { zend_error_noreturn(E_ERROR, "Arginfo / zpp mismatch during call of %s%s%s()", fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "", @@ -1353,10 +1325,10 @@ ZEND_API ZEND_COLD void zend_internal_call_arginfo_violation(zend_function *fbc) # define ZEND_VERIFY_FUNC_INFO 0 #endif -static void zend_verify_internal_func_info(zend_function *fn, zval *retval) { +static void zend_verify_internal_func_info(const zend_function *fn, const zval *retval) { #if ZEND_VERIFY_FUNC_INFO zend_string *name = fn->common.function_name; - uint32_t type_mask = zend_get_internal_func_info(fn, NULL, NULL); + const uint32_t type_mask = zend_get_internal_func_info(fn, NULL, NULL); if (!type_mask) { return; } @@ -1371,14 +1343,14 @@ static void zend_verify_internal_func_info(zend_function *fn, zval *retval) { } } - uint32_t type = 1u << Z_TYPE_P(retval); + const uint32_t type = 1u << Z_TYPE_P(retval); if (!(type_mask & type)) { zend_error_noreturn(E_CORE_ERROR, "%s() missing type %s", ZSTR_VAL(name), zend_get_type_by_const(Z_TYPE_P(retval))); } if (Z_TYPE_P(retval) == IS_ARRAY) { - HashTable *ht = Z_ARRVAL_P(retval); + const HashTable *ht = Z_ARRVAL_P(retval); uint32_t num_checked = 0; zend_string *str; zval *val; @@ -1395,7 +1367,7 @@ static void zend_verify_internal_func_info(zend_function *fn, zval *retval) { } } - uint32_t array_type = 1u << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT); + const uint32_t array_type = 1u << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT); if (!(type_mask & array_type)) { zend_error_noreturn(E_CORE_ERROR, "%s() missing array element type %s", @@ -1412,9 +1384,9 @@ static void zend_verify_internal_func_info(zend_function *fn, zval *retval) { } #endif -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data) +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(const zend_execute_data *execute_data) { - zend_execute_data *ptr = EX(prev_execute_data); + const zend_execute_data *ptr = EX(prev_execute_data); if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { zend_throw_error(zend_ce_argument_count_error, "Too few arguments to function %s%s%s(), %d passed in %s on line %d and %s %d expected", @@ -1437,7 +1409,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data * } } -ZEND_API ZEND_COLD void zend_verify_return_error(const zend_function *zf, zval *value) +ZEND_API ZEND_COLD void zend_verify_return_error(const zend_function *zf, const zval *value) { const zend_arg_info *arg_info = &zf->common.arg_info[-1]; const char *fname, *fsep, *fclass; @@ -1464,7 +1436,7 @@ ZEND_API ZEND_COLD void zend_verify_never_error(const zend_function *zf) } #if ZEND_DEBUG -static ZEND_COLD void zend_verify_internal_return_error(const zend_function *zf, zval *value) +static ZEND_COLD void zend_verify_internal_return_error(const zend_function *zf, const zval *value) { const zend_arg_info *arg_info = &zf->common.arg_info[-1]; const char *fname, *fsep, *fclass; @@ -1496,9 +1468,9 @@ static ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, con fclass, fsep, fname, returned_msg, returned_kind); } -ZEND_API bool zend_verify_internal_return_type(zend_function *zf, zval *ret) +ZEND_API bool zend_verify_internal_return_type(const zend_function *zf, zval *ret) { - zend_internal_arg_info *ret_info = zf->internal_function.arg_info - 1; + const zend_internal_arg_info *ret_info = zf->internal_function.arg_info - 1; if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_VOID) { if (UNEXPECTED(Z_TYPE_P(ret) != IS_NULL)) { @@ -1508,7 +1480,7 @@ ZEND_API bool zend_verify_internal_return_type(zend_function *zf, zval *ret) return 1; } - if (UNEXPECTED(!zend_check_type(&ret_info->type, ret, /* cache_slot */ NULL, NULL, 1, /* is_internal */ 1))) { + if (UNEXPECTED(!zend_check_type(&ret_info->type, ret, NULL, 1, /* is_internal */ 1))) { zend_verify_internal_return_error(zf, ret); return 0; } @@ -1523,7 +1495,7 @@ static ZEND_COLD void zend_verify_missing_return_type(const zend_function *zf) zend_verify_return_error(zf, NULL); } -static zend_always_inline bool zend_check_class_constant_type(zend_class_constant *c, zval *constant) +static zend_always_inline bool zend_check_class_constant_type(const zend_class_constant *c, zval *constant) { ZEND_ASSERT(!Z_ISREF_P(constant)); if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(c->type, Z_TYPE_P(constant)))) { @@ -1540,7 +1512,7 @@ static zend_always_inline bool zend_check_class_constant_type(zend_class_constan return zend_verify_scalar_type_hint(type_mask, constant, true, false); } -ZEND_API bool zend_never_inline zend_verify_class_constant_type(zend_class_constant *c, const zend_string *name, zval *constant) +ZEND_API bool zend_never_inline zend_verify_class_constant_type(const zend_class_constant *c, const zend_string *name, zval *constant) { if (!zend_check_class_constant_type(c, constant)) { zend_verify_class_constant_type_error(c, name, constant); @@ -1709,7 +1681,7 @@ static zend_never_inline void zend_binary_assign_op_typed_ref(zend_reference *re } } -static zend_never_inline void zend_binary_assign_op_typed_prop(zend_property_info *prop_info, zval *zptr, zval *value OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void zend_binary_assign_op_typed_prop(const zend_property_info *prop_info, zval *zptr, zval *value OPLINE_DC EXECUTE_DATA_DC) { zval z_copy; @@ -1850,14 +1822,14 @@ ZEND_COLD static zend_result ZEND_FASTCALL get_deprecation_suffix_from_attribute z = zend_read_property_ex(zend_ce_deprecated, Z_OBJ_P(&obj), ZSTR_KNOWN(ZEND_STR_MESSAGE), false, NULL); ZEND_ASSERT(z != &EG(uninitialized_zval)); if (Z_TYPE_P(z) == IS_STRING) { - message = zend_string_copy(Z_STR_P(z)); + message = Z_STR_P(z); } /* Extract the $since property. */ z = zend_read_property_ex(zend_ce_deprecated, Z_OBJ_P(&obj), ZSTR_KNOWN(ZEND_STR_SINCE), false, NULL); ZEND_ASSERT(z != &EG(uninitialized_zval)); if (Z_TYPE_P(z) == IS_STRING) { - since = zend_string_copy(Z_STR_P(z)); + since = Z_STR_P(z); } /* Construct the suffix. */ @@ -1874,8 +1846,6 @@ ZEND_COLD static zend_result ZEND_FASTCALL get_deprecation_suffix_from_attribute out: - zend_string_release(since); - zend_string_release(message); zval_ptr_dtor(&obj); return result; @@ -1907,6 +1877,87 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_functi zend_string_release(message_suffix); } +ZEND_COLD static zend_result ZEND_FASTCALL get_nodiscard_suffix_from_attribute(HashTable *attributes, zend_class_entry* scope, zend_string **message_suffix) +{ + *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (!attributes) { + return SUCCESS; + } + + zend_attribute *nodiscard = zend_get_attribute_str(attributes, "nodiscard", sizeof("nodiscard")-1); + + if (!nodiscard) { + return SUCCESS; + } + + if (nodiscard->argc == 0) { + return SUCCESS; + } + + zend_result result = FAILURE; + + zend_string *message = ZSTR_EMPTY_ALLOC(); + + zval obj; + ZVAL_UNDEF(&obj); + zval *z; + + /* Construct the NoDiscard object to correctly handle parameter processing. */ + if (FAILURE == zend_get_attribute_object(&obj, zend_ce_nodiscard, nodiscard, scope, NULL)) { + goto out; + } + + /* Extract the $message property. */ + z = zend_read_property_ex(zend_ce_nodiscard, Z_OBJ_P(&obj), ZSTR_KNOWN(ZEND_STR_MESSAGE), false, NULL); + ZEND_ASSERT(z != &EG(uninitialized_zval)); + if (Z_TYPE_P(z) == IS_STRING) { + message = Z_STR_P(z); + } + + /* Construct the suffix. */ + *message_suffix = zend_strpprintf_unchecked( + 0, + "%s%S", + ZSTR_LEN(message) > 0 ? ", " : "", + message + ); + + result = SUCCESS; + + out: + + zval_ptr_dtor(&obj); + + return result; +} + +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_nodiscard_function(const zend_function *fbc) +{ + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (get_nodiscard_suffix_from_attribute(fbc->common.attributes, fbc->common.scope, &message_suffix) == FAILURE) { + return; + } + + int code = fbc->type == ZEND_INTERNAL_FUNCTION ? E_WARNING : E_USER_WARNING; + + if (fbc->common.scope) { + zend_error_unchecked(code, "The return value of method %s::%s() should either be used or intentionally ignored by casting it as (void)%S", + ZSTR_VAL(fbc->common.scope->name), + ZSTR_VAL(fbc->common.function_name), + message_suffix + ); + } else { + zend_error_unchecked(code, "The return value of function %s() should either be used or intentionally ignored by casting it as (void)%S", + ZSTR_VAL(fbc->common.function_name), + message_suffix + ); + } + + zend_string_release(message_suffix); +} + ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_class_constant *c, const zend_string *constant_name) { zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 3b8ed89ec4f38..b9fef311d9f9b 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -60,8 +60,9 @@ ZEND_API zend_result zend_eval_stringl_ex(const char *str, size_t str_len, zval /* export zend_pass_function to allow comparisons against it */ extern ZEND_API const zend_internal_function zend_pass_function; -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data); +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(const zend_execute_data *execute_data); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc); +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_nodiscard_function(const zend_function *fbc); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_class_constant *c, const zend_string *constant_name); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void); ZEND_COLD void ZEND_FASTCALL zend_param_must_be_ref(const zend_function *func, uint32_t arg_num); @@ -94,23 +95,23 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_object_released_while_assigning_to_pr ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_add_element(void); ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_property_info *prop_info); -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_asymmetric_visibility_property_modification_error(const zend_property_info *info, const char *operation); +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_asymmetric_visibility_property_modification_error(const zend_property_info *prop_info, const char *operation); ZEND_API bool zend_verify_scalar_type_hint(uint32_t type_mask, zval *arg, bool strict, bool is_internal_arg); ZEND_API ZEND_COLD void zend_verify_arg_error( - const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, zval *value); + const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, const zval *value); ZEND_API ZEND_COLD void zend_verify_return_error( - const zend_function *zf, zval *value); + const zend_function *zf, const zval *value); ZEND_API ZEND_COLD void zend_verify_never_error( const zend_function *zf); ZEND_API bool zend_verify_ref_array_assignable(zend_reference *ref); ZEND_API bool zend_check_user_type_slow( - zend_type *type, zval *arg, zend_reference *ref, void **cache_slot, bool is_return_type); + const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type); #if ZEND_DEBUG -ZEND_API bool zend_internal_call_should_throw(zend_function *fbc, zend_execute_data *call); -ZEND_API ZEND_COLD void zend_internal_call_arginfo_violation(zend_function *fbc); -ZEND_API bool zend_verify_internal_return_type(zend_function *zf, zval *ret); +ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_execute_data *call); +ZEND_API ZEND_COLD void zend_internal_call_arginfo_violation(const zend_function *fbc); +ZEND_API bool zend_verify_internal_return_type(const zend_function *zf, zval *ret); #endif #define ZEND_REF_TYPE_SOURCES(ref) \ @@ -218,6 +219,60 @@ static zend_always_inline void zend_safe_assign_to_variable_noref(zval *variable } } +static zend_always_inline void zend_cast_zval_to_object(zval *result, zval *expr, uint8_t op1_type) { + HashTable *ht; + + ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); + if (Z_TYPE_P(expr) == IS_ARRAY) { + ht = zend_symtable_to_proptable(Z_ARR_P(expr)); + if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { + /* TODO: try not to duplicate immutable arrays as well ??? */ + ht = zend_array_dup(ht); + } + Z_OBJ_P(result)->properties = ht; + } else if (Z_TYPE_P(expr) != IS_NULL) { + Z_OBJ_P(result)->properties = ht = zend_new_array(1); + expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); + if (op1_type == IS_CONST) { + if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); + } else { + if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); + } + } +} + +static zend_always_inline void zend_cast_zval_to_array(zval *result, zval *expr, uint8_t op1_type) { + extern zend_class_entry *zend_ce_closure; + if (op1_type == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { + if (Z_TYPE_P(expr) != IS_NULL) { + ZVAL_ARR(result, zend_new_array(1)); + expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); + if (op1_type == IS_CONST) { + if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); + } else { + if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); + } + } else { + ZVAL_EMPTY_ARRAY(result); + } + } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { + /* Optimized version without rebuilding properties HashTable */ + ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); + } else { + HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); + if (obj_ht) { + /* fast copy */ + ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, + (Z_OBJCE_P(expr)->default_properties_count || + Z_OBJ_P(expr)->handlers != &std_object_handlers || + GC_IS_RECURSIVE(obj_ht)))); + zend_release_properties(obj_ht); + } else { + ZVAL_EMPTY_ARRAY(result); + } + } +} + ZEND_API zend_result ZEND_FASTCALL zval_update_constant(zval *pp); ZEND_API zend_result ZEND_FASTCALL zval_update_constant_ex(zval *pp, zend_class_entry *scope); ZEND_API zend_result ZEND_FASTCALL zval_update_constant_with_ctx(zval *pp, zend_class_entry *scope, zend_ast_evaluate_ctx *ctx); @@ -521,7 +576,7 @@ ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *cal #define ZEND_CLASS_HAS_READONLY_PROPS(ce) ((bool)(ce->ce_flags & ZEND_ACC_HAS_READONLY_PROPS)) -ZEND_API bool zend_verify_class_constant_type(zend_class_constant *c, const zend_string *name, zval *constant); +ZEND_API bool zend_verify_class_constant_type(const zend_class_constant *c, const zend_string *name, zval *constant); ZEND_COLD void zend_verify_class_constant_type_error(const zend_class_constant *c, const zend_string *name, const zval *constant); ZEND_API bool zend_verify_property_type(const zend_property_info *info, zval *property, bool strict); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 1f55521fb72f1..12df2a9ee5b99 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -53,10 +53,6 @@ ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data); ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value); ZEND_API zend_class_entry *(*zend_autoload)(zend_string *name, zend_string *lc_name); -/* true globals */ -ZEND_API const zend_fcall_info empty_fcall_info = {0}; -ZEND_API const zend_fcall_info_cache empty_fcall_info_cache = {0}; - #ifdef ZEND_WIN32 ZEND_TLS HANDLE tq_timer = NULL; #endif diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index 69bbca242b4ff..8da55fcd48f66 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -1917,7 +1917,7 @@ ZEND_API int zend_gc_collect_cycles(void) bool did_rerun_gc = 0; zend_hrtime_t start_time = zend_hrtime(); - if (GC_G(num_roots) && GC_G(gc_active)) { + if (GC_G(num_roots) && !GC_G(gc_active)) { zend_gc_remove_root_tmpvars(); } diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index d543dae2bab59..b2aaecce0d27c 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -261,7 +261,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_end_ex(const HashTable * static zend_always_inline zend_result zend_hash_has_more_elements_ex(const HashTable *ht, const HashPosition *pos) { return (zend_hash_get_current_key_type_ex(ht, pos) == HASH_KEY_NON_EXISTENT ? FAILURE : SUCCESS); } -static zend_always_inline zend_result zend_hash_has_more_elements(HashTable *ht) { +static zend_always_inline zend_result zend_hash_has_more_elements(const HashTable *ht) { return zend_hash_has_more_elements_ex(ht, &ht->nInternalPointer); } static zend_always_inline zend_result zend_hash_move_forward(HashTable *ht) { @@ -554,7 +554,7 @@ static zend_always_inline zval *zend_symtable_find_ind(const HashTable *ht, zend } -static zend_always_inline bool zend_symtable_exists(HashTable *ht, zend_string *key) +static zend_always_inline bool zend_symtable_exists(const HashTable *ht, zend_string *key) { zend_ulong idx; @@ -566,7 +566,7 @@ static zend_always_inline bool zend_symtable_exists(HashTable *ht, zend_string * } -static zend_always_inline bool zend_symtable_exists_ind(HashTable *ht, zend_string *key) +static zend_always_inline bool zend_symtable_exists_ind(const HashTable *ht, zend_string *key) { zend_ulong idx; @@ -937,7 +937,7 @@ static zend_always_inline void *zend_hash_index_find_ptr(const HashTable *ht, ze } } -static zend_always_inline zval *zend_hash_index_find_deref(HashTable *ht, zend_ulong h) +static zend_always_inline zval *zend_hash_index_find_deref(const HashTable *ht, zend_ulong h) { zval *zv = zend_hash_index_find(ht, h); if (zv) { @@ -946,7 +946,7 @@ static zend_always_inline zval *zend_hash_index_find_deref(HashTable *ht, zend_u return zv; } -static zend_always_inline zval *zend_hash_find_deref(HashTable *ht, zend_string *str) +static zend_always_inline zval *zend_hash_find_deref(const HashTable *ht, zend_string *str) { zval *zv = zend_hash_find(ht, str); if (zv) { @@ -955,7 +955,7 @@ static zend_always_inline zval *zend_hash_find_deref(HashTable *ht, zend_string return zv; } -static zend_always_inline zval *zend_hash_str_find_deref(HashTable *ht, const char *str, size_t len) +static zend_always_inline zval *zend_hash_str_find_deref(const HashTable *ht, const char *str, size_t len) { zval *zv = zend_hash_str_find(ht, str, len); if (zv) { @@ -964,7 +964,7 @@ static zend_always_inline zval *zend_hash_str_find_deref(HashTable *ht, const ch return zv; } -static zend_always_inline void *zend_symtable_str_find_ptr(HashTable *ht, const char *str, size_t len) +static zend_always_inline void *zend_symtable_str_find_ptr(const HashTable *ht, const char *str, size_t len) { zend_ulong idx; @@ -975,7 +975,7 @@ static zend_always_inline void *zend_symtable_str_find_ptr(HashTable *ht, const } } -static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht, HashPosition *pos) +static zend_always_inline void *zend_hash_get_current_data_ptr_ex(const HashTable *ht, const HashPosition *pos) { zval *zv; diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 807c902276a24..090b1049418d2 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -83,7 +83,7 @@ static void zend_type_list_copy_ctor( } zend_type *list_type; - ZEND_TYPE_LIST_FOREACH(new_list, list_type) { + ZEND_TYPE_LIST_FOREACH_MUTABLE(new_list, list_type) { zend_type_copy_ctor(list_type, use_arena, persistent); } ZEND_TYPE_LIST_FOREACH_END(); } @@ -96,7 +96,7 @@ static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool pers } } -static zend_function *zend_duplicate_internal_function(zend_function *func, const zend_class_entry *ce) /* {{{ */ +static zend_function *zend_duplicate_internal_function(const zend_function *func, const zend_class_entry *ce) /* {{{ */ { zend_function *new_function; @@ -310,7 +310,7 @@ static zend_class_entry *lookup_class(zend_class_entry *scope, zend_string *name } /* Instanceof that's safe to use on unlinked classes. */ -static bool unlinked_instanceof(zend_class_entry *ce1, const zend_class_entry *ce2) { +static bool unlinked_instanceof(const zend_class_entry *ce1, const zend_class_entry *ce2) { if (ce1 == ce2) { return 1; } @@ -347,7 +347,7 @@ static bool unlinked_instanceof(zend_class_entry *ce1, const zend_class_entry *c } } else { for (i = 0; i < ce1->num_interfaces; i++) { - zend_class_entry *ce = zend_lookup_class_ex( + const zend_class_entry *ce = zend_lookup_class_ex( ce1->interface_names[i].name, ce1->interface_names[i].lc_name, ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD); /* Avoid recursing if class implements itself. */ @@ -362,7 +362,7 @@ static bool unlinked_instanceof(zend_class_entry *ce1, const zend_class_entry *c } static bool zend_type_permits_self( - zend_type type, zend_class_entry *scope, zend_class_entry *self) { + const zend_type type, const zend_class_entry *scope, zend_class_entry *self) { if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_OBJECT) { return 1; } @@ -370,11 +370,11 @@ static bool zend_type_permits_self( /* Any types that may satisfy self must have already been loaded at this point * (as a parent or interface), so we never need to register delayed variance obligations * for this case. */ - zend_type *single_type; + const zend_type *single_type; ZEND_TYPE_FOREACH(type, single_type) { if (ZEND_TYPE_HAS_NAME(*single_type)) { zend_string *name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type)); - zend_class_entry *ce = lookup_class(self, name); + const zend_class_entry *ce = lookup_class(self, name); if (ce && unlinked_instanceof(self, ce)) { return 1; } @@ -428,12 +428,12 @@ static void track_class_dependency(zend_class_entry *ce, zend_string *class_name /* Check whether any type in the fe_type intersection type is a subtype of the proto class. */ static inheritance_status zend_is_intersection_subtype_of_class( - zend_class_entry *fe_scope, zend_type fe_type, + zend_class_entry *fe_scope, const zend_type fe_type, zend_class_entry *proto_scope, zend_string *proto_class_name, zend_class_entry *proto_ce) { ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(fe_type)); bool have_unresolved = false; - zend_type *single_type; + const zend_type *single_type; /* Traverse the list of child types and check that at least one is * a subtype of the parent type being checked */ @@ -473,7 +473,7 @@ static inheritance_status zend_is_intersection_subtype_of_class( /* Check whether a single class proto type is a subtype of a potentially complex fe_type. */ static inheritance_status zend_is_class_subtype_of_type( zend_class_entry *fe_scope, zend_string *fe_class_name, - zend_class_entry *proto_scope, zend_type proto_type) { + zend_class_entry *proto_scope, const zend_type proto_type) { zend_class_entry *fe_ce = NULL; bool have_unresolved = 0; @@ -513,7 +513,7 @@ static inheritance_status zend_is_class_subtype_of_type( } } - zend_type *single_type; + const zend_type *single_type; /* Traverse the list of parent types and check if the current child (FE) * class is the subtype of at least one of them (union) or all of them (intersection). */ @@ -584,15 +584,15 @@ static inheritance_status zend_is_class_subtype_of_type( return is_intersection ? INHERITANCE_SUCCESS : INHERITANCE_ERROR; } -static zend_string *get_class_from_type(zend_class_entry *scope, zend_type single_type) { +static zend_string *get_class_from_type(const zend_class_entry *scope, const zend_type single_type) { if (ZEND_TYPE_HAS_NAME(single_type)) { return resolve_class_name(scope, ZEND_TYPE_NAME(single_type)); } return NULL; } -static void register_unresolved_classes(zend_class_entry *scope, zend_type type) { - zend_type *single_type; +static void register_unresolved_classes(zend_class_entry *scope, const zend_type type) { + const zend_type *single_type; ZEND_TYPE_FOREACH(type, single_type) { if (ZEND_TYPE_HAS_LIST(*single_type)) { register_unresolved_classes(scope, *single_type); @@ -606,11 +606,11 @@ static void register_unresolved_classes(zend_class_entry *scope, zend_type type) } static inheritance_status zend_is_intersection_subtype_of_type( - zend_class_entry *fe_scope, zend_type fe_type, - zend_class_entry *proto_scope, zend_type proto_type) + zend_class_entry *fe_scope, const zend_type fe_type, + zend_class_entry *proto_scope, const zend_type proto_type) { bool have_unresolved = false; - zend_type *single_type; + const zend_type *single_type; uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type); /* Currently, for object type any class name would be allowed here. @@ -672,8 +672,8 @@ static inheritance_status zend_is_intersection_subtype_of_type( } ZEND_API inheritance_status zend_perform_covariant_type_check( - zend_class_entry *fe_scope, zend_type fe_type, - zend_class_entry *proto_scope, zend_type proto_type) + zend_class_entry *fe_scope, const zend_type fe_type, + zend_class_entry *proto_scope, const zend_type proto_type) { ZEND_ASSERT(ZEND_TYPE_IS_SET(fe_type) && ZEND_TYPE_IS_SET(proto_type)); @@ -706,7 +706,6 @@ ZEND_API inheritance_status zend_perform_covariant_type_check( } } - zend_type *single_type; inheritance_status early_exit_status; bool have_unresolved = false; @@ -728,6 +727,7 @@ ZEND_API inheritance_status zend_perform_covariant_type_check( * We need to iterate over fe_type (U_i) first and the logic is independent of * whether proto_type is a union or intersection (only the inner check differs). */ early_exit_status = INHERITANCE_ERROR; + const zend_type *single_type; ZEND_TYPE_FOREACH(fe_type, single_type) { inheritance_status status; /* Union has an intersection type as it's member */ @@ -790,7 +790,7 @@ static inheritance_status zend_do_perform_implementation_check( const zend_function *fe, zend_class_entry *fe_scope, const zend_function *proto, zend_class_entry *proto_scope) /* {{{ */ { - uint32_t i, num_args, proto_num_args, fe_num_args; + uint32_t num_args, proto_num_args, fe_num_args; inheritance_status status, local_status; bool proto_is_variadic, fe_is_variadic; @@ -831,7 +831,7 @@ static inheritance_status zend_do_perform_implementation_check( num_args = MAX(proto_num_args, fe_num_args); status = INHERITANCE_SUCCESS; - for (i = 0; i < num_args; i++) { + for (uint32_t i = 0; i < num_args; i++) { zend_arg_info *proto_arg_info = i < proto_num_args ? &proto->common.arg_info[i] : proto_is_variadic ? &proto->common.arg_info[proto_num_args - 1] : NULL; @@ -933,7 +933,7 @@ static ZEND_COLD zend_string *zend_get_function_declaration( smart_str_appendc(&str, '('); if (fptr->common.arg_info) { - uint32_t i, num_args, required; + uint32_t num_args, required; zend_arg_info *arg_info = fptr->common.arg_info; required = fptr->common.required_num_args; @@ -941,7 +941,7 @@ static ZEND_COLD zend_string *zend_get_function_declaration( if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) { num_args++; } - for (i = 0; i < num_args;) { + for (uint32_t i = 0; i < num_args;) { zend_append_type_hint(&str, scope, arg_info, 0); if (ZEND_ARG_SEND_MODE(arg_info)) { @@ -973,7 +973,7 @@ static ZEND_COLD zend_string *zend_get_function_declaration( { uint32_t idx = i; zend_op *op = fptr->op_array.opcodes; - zend_op *end = op + fptr->op_array.last; + const zend_op *end = op + fptr->op_array.last; ++idx; while (op < end) { @@ -1135,7 +1135,12 @@ static inheritance_status do_inheritance_check_on_method( #define SEPARATE_METHOD() do { \ if ((flags & ZEND_INHERITANCE_LAZY_CHILD_CLONE) \ - && child_scope != ce && child->type == ZEND_USER_FUNCTION) { \ + && child_scope != ce \ + /* Trait methods have already been separated at this point. However, their */ \ + /* scope isn't fixed until after inheritance checks to preserve the scope */ \ + /* in error messages. Skip them here explicitly. */ \ + && !(child_scope->ce_flags & ZEND_ACC_TRAIT) \ + && child->type == ZEND_USER_FUNCTION) { \ /* op_array wasn't duplicated yet */ \ zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); \ memcpy(new_function, child, sizeof(zend_op_array)); \ @@ -1361,7 +1366,7 @@ static inheritance_status verify_property_type_compatibility( return INHERITANCE_SUCCESS; } -static bool property_has_operation(zend_property_info *prop_info, zend_property_hook_kind kind) +static bool property_has_operation(const zend_property_info *prop_info, zend_property_hook_kind kind) { return (!(prop_info->flags & ZEND_ACC_VIRTUAL) && (kind == ZEND_PROPERTY_HOOK_GET || !(prop_info->flags & ZEND_ACC_READONLY))) @@ -1446,10 +1451,9 @@ static prop_variance prop_get_variance(const zend_property_info *prop_info) { static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */ { zval *child = zend_hash_find_known_hash(&ce->properties_info, key); - zend_property_info *child_info; if (UNEXPECTED(child)) { - child_info = Z_PTR_P(child); + zend_property_info *child_info = Z_PTR_P(child); if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED)) { child_info->flags |= ZEND_ACC_CHANGED; } @@ -1591,7 +1595,6 @@ static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_en { /* expects interface to be contained in ce's interface list already */ uint32_t i, ce_num, if_num = iface->num_interfaces; - zend_class_entry *entry; ce_num = ce->num_interfaces; @@ -1603,7 +1606,7 @@ static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_en /* Inherit the interfaces, only if they're not already inherited by the class */ while (if_num--) { - entry = iface->interfaces[if_num]; + zend_class_entry *entry = iface->interfaces[if_num]; for (i = 0; i < ce_num; i++) { if (ce->interfaces[i] == entry) { break; @@ -1646,7 +1649,7 @@ static inheritance_status class_constant_types_compatible(const zend_class_const } static bool do_inherit_constant_check( - zend_class_entry *ce, zend_class_constant *parent_constant, zend_string *name); + zend_class_entry *ce, const zend_class_constant *parent_constant, zend_string *name); static void do_inherit_class_constant(zend_string *name, zend_class_constant *parent_const, zend_class_entry *ce) /* {{{ */ { @@ -1719,7 +1722,7 @@ void zend_build_properties_info_table(zend_class_entry *ce) } ZEND_HASH_FOREACH_END(); } -ZEND_API void zend_verify_hooked_property(zend_class_entry *ce, zend_property_info *prop_info, zend_string *prop_name) +ZEND_API void zend_verify_hooked_property(const zend_class_entry *ce, zend_property_info *prop_info, zend_string *prop_name) { if (!prop_info->hooks) { return; @@ -1743,7 +1746,7 @@ ZEND_API void zend_verify_hooked_property(zend_class_entry *ce, zend_property_in ZVAL_NULL(&ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]); } for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) { - zend_function *func = prop_info->hooks[i]; + const zend_function *func = prop_info->hooks[i]; if (func) { if ((zend_property_hook_kind)i == ZEND_PROPERTY_HOOK_GET && (func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) @@ -1825,7 +1828,6 @@ static void zend_link_hooked_object_iter(zend_class_entry *ce) { ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *parent_ce, bool checked) /* {{{ */ { zend_property_info *property_info; - zend_function *func; zend_string *key; if (UNEXPECTED(ce->ce_flags & ZEND_ACC_INTERFACE)) { @@ -2016,6 +2018,7 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par if (!checked) { flags |= ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY; } + zend_function *func; ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) { do_inherit_method(key, func, ce, 0, flags); } ZEND_HASH_FOREACH_END(); @@ -2074,7 +2077,7 @@ static zend_always_inline bool check_trait_property_or_constant_value_compatibil /** @return bool Returns true if the class constant should be inherited, i.e. whether it doesn't already exist. */ static bool do_inherit_constant_check( - zend_class_entry *ce, zend_class_constant *parent_constant, zend_string *name + zend_class_entry *ce, const zend_class_constant *parent_constant, zend_string *name ) { zval *zv = zend_hash_find_known_hash(&ce->constants_table, name); if (zv == NULL) { @@ -2121,7 +2124,7 @@ static bool do_inherit_constant_check( } /* }}} */ -static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */ +static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */ { if (do_inherit_constant_check(ce, c, name)) { zend_class_constant *ct; @@ -2191,27 +2194,27 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry * ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */ { - uint32_t i, ignore = 0; + bool ignore = false; uint32_t current_iface_num = ce->num_interfaces; uint32_t parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0; - zend_string *key; - zend_class_constant *c; ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED); - for (i = 0; i < ce->num_interfaces; i++) { + for (uint32_t i = 0; i < ce->num_interfaces; i++) { if (ce->interfaces[i] == NULL) { memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i)); i--; } else if (ce->interfaces[i] == iface) { if (EXPECTED(i < parent_iface_num)) { - ignore = 1; + ignore = true; } else { zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name)); } } } if (ignore) { + zend_string *key; + zend_class_constant *c; /* Check for attempt to redeclare interface constants */ ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) { do_inherit_constant_check(ce, c, key); @@ -2233,15 +2236,14 @@ ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry **interfaces) /* {{{ */ { - zend_class_entry *iface; uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0; uint32_t num_interfaces = num_parent_interfaces; zend_string *key; zend_class_constant *c; - uint32_t i, j; + uint32_t i; for (i = 0; i < ce->num_interfaces; i++) { - iface = interfaces[num_parent_interfaces + i]; + zend_class_entry *iface = interfaces[num_parent_interfaces + i]; if (!(iface->ce_flags & ZEND_ACC_LINKED)) { add_dependency_obligation(ce, iface); } @@ -2250,7 +2252,7 @@ static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name)); return; } - for (j = 0; j < num_interfaces; j++) { + for (uint32_t j = 0; j < num_interfaces; j++) { if (interfaces[j] == iface) { if (j >= num_parent_interfaces) { efree(interfaces); @@ -2299,7 +2301,7 @@ static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry /* }}} */ -void zend_inheritance_check_override(zend_class_entry *ce) +void zend_inheritance_check_override(const zend_class_entry *ce) { zend_function *f; @@ -2350,7 +2352,6 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_ { zend_function *existing_fn = NULL; zend_function *new_fn; - bool check_inheritance = false; if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) { /* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless @@ -2384,8 +2385,6 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_ ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name), ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name)); - } else { - check_inheritance = true; } } @@ -2405,19 +2404,6 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_ function_add_ref(new_fn); fn = zend_hash_update_ptr(&ce->function_table, key, new_fn); zend_add_magic_method(ce, fn, key); - - if (check_inheritance) { - /* Inherited members are overridden by members inserted by traits. - * Check whether the trait method fulfills the inheritance requirements. */ - uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY; - if (!(existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) { - flags |= ZEND_INHERITANCE_SET_CHILD_CHANGED |ZEND_INHERITANCE_SET_CHILD_PROTO | - ZEND_INHERITANCE_RESET_CHILD_OVERRIDE; - } - do_inheritance_check_on_method( - fn, fixup_trait_scope(fn, ce), existing_fn, fixup_trait_scope(existing_fn, ce), - ce, NULL, flags); - } } /* }}} */ @@ -2437,7 +2423,7 @@ static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* } /* }}} */ -static void zend_traits_check_private_final_inheritance(uint32_t original_fn_flags, zend_function *fn_copy, zend_string *name) +static void zend_traits_check_private_final_inheritance(uint32_t original_fn_flags, const zend_function *fn_copy, const zend_string *name) { /* If the function was originally already private+final, then it will have * already been warned about. Only emit this error when the used trait method @@ -2453,7 +2439,6 @@ static void zend_traits_check_private_final_inheritance(uint32_t original_fn_fla static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */ { zend_trait_alias *alias, **alias_ptr; - zend_string *lcname; zend_function fn_copy; int i; @@ -2477,7 +2462,7 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, alias->alias); - lcname = zend_string_tolower(alias->alias); + zend_string *lcname = zend_string_tolower(alias->alias); zend_add_trait_method(ce, alias->alias, lcname, &fn_copy); zend_string_release_ex(lcname, 0); } @@ -2521,16 +2506,14 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z } /* }}} */ -static uint32_t zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait, zend_class_entry **traits) /* {{{ */ +static uint32_t zend_check_trait_usage(const zend_class_entry *ce, const zend_class_entry *trait, zend_class_entry **traits) /* {{{ */ { - uint32_t i; - if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) { zend_error_noreturn(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", ZSTR_VAL(trait->name)); return 0; } - for (i = 0; i < ce->num_traits; i++) { + for (uint32_t i = 0; i < ce->num_traits; i++) { if (traits[i] == trait) { return i; } @@ -2543,7 +2526,6 @@ static uint32_t zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *t static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_entry **traits, HashTable ***exclude_tables_ptr, zend_class_entry ***aliases_ptr) /* {{{ */ { size_t i, j = 0; - zend_trait_precedence **precedences; zend_trait_precedence *cur_precedence; zend_trait_method_reference *cur_method_ref; zend_string *lc_trait_name; @@ -2556,7 +2538,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e if (ce->trait_precedences) { exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*)); i = 0; - precedences = ce->trait_precedences; + zend_trait_precedence **precedences = ce->trait_precedences; ce->trait_precedences = NULL; while ((cur_precedence = precedences[i])) { /** Resolve classes for all precedence operations. */ @@ -2630,7 +2612,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e aliases = ecalloc(i, sizeof(zend_class_entry*)); i = 0; while (ce->trait_aliases[i]) { - zend_trait_alias *cur_alias = ce->trait_aliases[i]; + const zend_trait_alias *cur_alias = ce->trait_aliases[i]; cur_method_ref = &ce->trait_aliases[i]->trait_method; lcname = zend_string_tolower(cur_method_ref->method_name); if (cur_method_ref->class_name) { @@ -2695,7 +2677,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e } /* }}} */ -static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases) /* {{{ */ +static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases, bool verify_abstract, bool *contains_abstract_methods) /* {{{ */ { uint32_t i; zend_string *key; @@ -2706,6 +2688,11 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry if (traits[i]) { /* copies functions, applies defined aliasing, and excludes unused trait methods */ ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) { + bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT); + *contains_abstract_methods |= is_abstract; + if (verify_abstract != is_abstract) { + continue; + } zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases); } ZEND_HASH_FOREACH_END(); @@ -2720,15 +2707,16 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry for (i = 0; i < ce->num_traits; i++) { if (traits[i]) { ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) { + bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT); + *contains_abstract_methods |= is_abstract; + if (verify_abstract != is_abstract) { + continue; + } zend_traits_copy_functions(key, fn, ce, NULL, aliases); } ZEND_HASH_FOREACH_END(); } } } - - ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) { - zend_fixup_trait_method(fn, ce); - } ZEND_HASH_FOREACH_END(); } /* }}} */ @@ -2741,10 +2729,8 @@ static const zend_class_entry* find_first_constant_definition(const zend_class_e * process like this is needed to find the location of the first definition * of the constant from traits. */ - size_t i; - if (colliding_ce == ce) { - for (i = 0; i < current_trait; i++) { + for (size_t i = 0; i < current_trait; i++) { if (traits[i] && zend_hash_exists(&traits[i]->constants_table, constant_name)) { return traits[i]; @@ -2811,9 +2797,7 @@ static bool do_trait_constant_check( static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */ { - size_t i; - - for (i = 0; i < ce->num_traits; i++) { + for (uint32_t i = 0; i < ce->num_traits; i++) { zend_string *constant_name; zend_class_constant *constant; @@ -2855,10 +2839,8 @@ static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_ent static const zend_class_entry* find_first_property_definition(const zend_class_entry *ce, zend_class_entry **traits, size_t current_trait, zend_string *prop_name, const zend_class_entry *colliding_ce) /* {{{ */ { - size_t i; - if (colliding_ce == ce) { - for (i = 0; i < current_trait; i++) { + for (size_t i = 0; i < current_trait; i++) { if (traits[i] && zend_hash_exists(&traits[i]->properties_info, prop_name)) { return traits[i]; @@ -2872,20 +2854,17 @@ static const zend_class_entry* find_first_property_definition(const zend_class_e static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */ { - size_t i; zend_property_info *property_info; const zend_property_info *colliding_prop; - zend_property_info *new_prop; zend_string* prop_name; zval* prop_value; - zend_string *doc_comment; /* In the following steps the properties are inserted into the property table * for that, a very strict approach is applied: * - check for compatibility, if not compatible with any property in class -> fatal * - if compatible, then strict notice */ - for (i = 0; i < ce->num_traits; i++) { + for (uint32_t i = 0; i < ce->num_traits; i++) { if (!traits[i]) { continue; } @@ -2965,12 +2944,13 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent prop_value = &tmp_prop_value; ZVAL_UNDEF(&tmp_prop_value); } - doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL; + + zend_string *doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL; zend_type type = property_info->type; /* Assumption: only userland classes can use traits, as such the type must be arena allocated */ zend_type_copy_ctor(&type, /* use arena */ true, /* persistent */ false); - new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type); + zend_property_info *new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type); if (property_info->attributes) { new_prop->attributes = property_info->attributes; @@ -2983,9 +2963,9 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent zend_function **hooks = new_prop->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE); memcpy(hooks, property_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE); - for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) { - if (hooks[i]) { - zend_function *old_fn = hooks[i]; + for (uint32_t j = 0; j < ZEND_PROPERTY_HOOK_COUNT; j++) { + if (hooks[j]) { + zend_function *old_fn = hooks[j]; /* Hooks are not yet supported for internal properties. */ ZEND_ASSERT(ZEND_USER_CODE(old_fn->type)); @@ -3000,7 +2980,7 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent zend_fixup_trait_method(new_fn, ce); - hooks[i] = new_fn; + hooks[j] = new_fn; } } ce->ce_flags |= ZEND_ACC_USE_GUARDS; @@ -3010,33 +2990,6 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent } /* }}} */ -static void zend_do_bind_traits(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */ -{ - HashTable **exclude_tables; - zend_class_entry **aliases; - - ZEND_ASSERT(ce->num_traits > 0); - - /* complete initialization of trait structures in ce */ - zend_traits_init_trait_structures(ce, traits, &exclude_tables, &aliases); - - /* first care about all methods to be flattened into the class */ - zend_do_traits_method_binding(ce, traits, exclude_tables, aliases); - - if (aliases) { - efree(aliases); - } - - if (exclude_tables) { - efree(exclude_tables); - } - - /* then flatten the constants and properties into it, to, mostly to notify developer about problems */ - zend_do_traits_constant_binding(ce, traits); - zend_do_traits_property_binding(ce, traits); -} -/* }}} */ - #define MAX_ABSTRACT_INFO_CNT 3 #define MAX_ABSTRACT_INFO_FMT "%s%s%s%s" #define DISPLAY_ABSTRACT_FN(idx) \ @@ -3253,7 +3206,7 @@ static void add_property_hook_obligation( static void resolve_delayed_variance_obligations(zend_class_entry *ce); -static void check_variance_obligation(variance_obligation *obligation) { +static void check_variance_obligation(const variance_obligation *obligation) { if (obligation->type == OBLIGATION_DEPENDENCY) { zend_class_entry *dependency_ce = obligation->dependency_ce; if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) { @@ -3292,7 +3245,7 @@ static void check_variance_obligation(variance_obligation *obligation) { } } -static void load_delayed_classes(zend_class_entry *ce) { +static void load_delayed_classes(const zend_class_entry *ce) { HashTable *delayed_autoloads = CG(delayed_autoloads); if (!delayed_autoloads) { return; @@ -3321,11 +3274,11 @@ static void load_delayed_classes(zend_class_entry *ce) { } static void resolve_delayed_variance_obligations(zend_class_entry *ce) { - HashTable *all_obligations = CG(delayed_variance_obligations), *obligations; + HashTable *all_obligations = CG(delayed_variance_obligations); zend_ulong num_key = (zend_ulong) (uintptr_t) ce; ZEND_ASSERT(all_obligations != NULL); - obligations = zend_hash_index_find_ptr(all_obligations, num_key); + const HashTable *obligations = zend_hash_index_find_ptr(all_obligations, num_key); ZEND_ASSERT(obligations != NULL); variance_obligation *obligation; @@ -3359,7 +3312,7 @@ static void check_unrecoverable_load_failure(const zend_class_entry *ce) { } while (0) static zend_op_array *zend_lazy_method_load( - zend_op_array *op_array, zend_class_entry *ce, const zend_class_entry *pce) { + const zend_op_array *op_array, zend_class_entry *ce, const zend_class_entry *pce) { ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION); ZEND_ASSERT(op_array->scope == pce); ZEND_ASSERT(op_array->prototype == NULL); @@ -3373,12 +3326,10 @@ static zend_op_array *zend_lazy_method_load( return new_op_array; } -static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce) +static zend_class_entry *zend_lazy_class_load(const zend_class_entry *pce) { - zend_class_entry *ce; - Bucket *p, *end; + zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry)); - ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry)); memcpy(ce, pce, sizeof(zend_class_entry)); ce->ce_flags &= ~ZEND_ACC_IMMUTABLE; ce->refcount = 1; @@ -3393,7 +3344,7 @@ static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce) if (ce->default_properties_table) { zval *dst = emalloc(sizeof(zval) * ce->default_properties_count); zval *src = ce->default_properties_table; - zval *end = src + ce->default_properties_count; + const zval *end = src + ce->default_properties_count; ce->default_properties_table = dst; for (; src != end; src++, dst++) { @@ -3404,11 +3355,11 @@ static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce) /* methods */ ce->function_table.pDestructor = ZEND_FUNCTION_DTOR; if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) { - p = emalloc(HT_SIZE(&ce->function_table)); + Bucket *p = emalloc(HT_SIZE(&ce->function_table)); memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table)); HT_SET_DATA_ADDR(&ce->function_table, p); p = ce->function_table.arData; - end = p + ce->function_table.nNumUsed; + const Bucket *end = p + ce->function_table.nNumUsed; for (; p != end; p++) { zend_op_array *op_array = Z_PTR(p->val); zend_op_array *new_op_array = Z_PTR(p->val) = zend_lazy_method_load(op_array, ce, pce); @@ -3433,7 +3384,7 @@ static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce) if (ce->default_static_members_table) { zval *dst = emalloc(sizeof(zval) * ce->default_static_members_count); zval *src = ce->default_static_members_table; - zval *end = src + ce->default_static_members_count; + const zval *end = src + ce->default_static_members_count; ce->default_static_members_table = dst; for (; src != end; src++, dst++) { @@ -3444,15 +3395,15 @@ static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce) /* properties_info */ if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) { - p = emalloc(HT_SIZE(&ce->properties_info)); + Bucket *p = emalloc(HT_SIZE(&ce->properties_info)); memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info)); HT_SET_DATA_ADDR(&ce->properties_info, p); p = ce->properties_info.arData; - end = p + ce->properties_info.nNumUsed; + const Bucket *end = p + ce->properties_info.nNumUsed; for (; p != end; p++) { - zend_property_info *prop_info, *new_prop_info; + zend_property_info *new_prop_info; - prop_info = Z_PTR(p->val); + const zend_property_info *prop_info = Z_PTR(p->val); ZEND_ASSERT(prop_info->ce == pce); ZEND_ASSERT(prop_info->prototype == prop_info); new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info)); @@ -3480,15 +3431,15 @@ static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce) /* constants table */ if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) { - p = emalloc(HT_SIZE(&ce->constants_table)); + Bucket *p = emalloc(HT_SIZE(&ce->constants_table)); memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table)); HT_SET_DATA_ADDR(&ce->constants_table, p); p = ce->constants_table.arData; - end = p + ce->constants_table.nNumUsed; + const Bucket *end = p + ce->constants_table.nNumUsed; for (; p != end; p++) { - zend_class_constant *c, *new_c; + zend_class_constant *new_c; - c = Z_PTR(p->val); + const zend_class_constant *c = Z_PTR(p->val); ZEND_ASSERT(c->ce == pce); new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant)); Z_PTR(p->val) = new_c; @@ -3513,7 +3464,7 @@ static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce) } while (0) #endif -ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, zend_string *key) /* {{{ */ +ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, const zend_string *key) /* {{{ */ { /* Load parent/interface dependencies first, so we can still gracefully abort linking * with an exception and remove the class from the class table. This is only possible @@ -3546,13 +3497,13 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string for (i = 0; i < ce->num_traits; i++) { zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name, - ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT); + ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(trait == NULL)) { free_alloca(traits_and_interfaces, use_heap); return NULL; } if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) { - zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name)); + zend_throw_error(NULL, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name)); free_alloca(traits_and_interfaces, use_heap); return NULL; } @@ -3649,6 +3600,15 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string zend_link_hooked_object_iter(ce); #endif + HashTable **trait_exclude_tables; + zend_class_entry **trait_aliases; + bool trait_contains_abstract_methods = false; + if (ce->num_traits) { + zend_traits_init_trait_structures(ce, traits_and_interfaces, &trait_exclude_tables, &trait_aliases); + zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, false, &trait_contains_abstract_methods); + zend_do_traits_constant_binding(ce, traits_and_interfaces); + zend_do_traits_property_binding(ce, traits_and_interfaces); + } if (parent) { if (!(parent->ce_flags & ZEND_ACC_LINKED)) { add_dependency_obligation(ce, parent); @@ -3656,7 +3616,29 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string zend_do_inheritance(ce, parent); } if (ce->num_traits) { - zend_do_bind_traits(ce, traits_and_interfaces); + if (trait_contains_abstract_methods) { + zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, true, &trait_contains_abstract_methods); + } + + if (trait_exclude_tables) { + for (i = 0; i < ce->num_traits; i++) { + if (traits_and_interfaces[i]) { + if (trait_exclude_tables[i]) { + zend_hash_destroy(trait_exclude_tables[i]); + FREE_HASHTABLE(trait_exclude_tables[i]); + } + } + } + efree(trait_exclude_tables); + } + if (trait_aliases) { + efree(trait_aliases); + } + + zend_function *fn; + ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) { + zend_fixup_trait_method(fn, ce); + } ZEND_HASH_FOREACH_END(); } if (ce->num_interfaces) { /* Also copy the parent interfaces here, so we don't need to reallocate later. */ @@ -3785,7 +3767,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string /* }}} */ /* Check whether early binding is prevented due to unresolved types in inheritance checks. */ -static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce) /* {{{ */ +static inheritance_status zend_can_early_bind(zend_class_entry *ce, const zend_class_entry *parent_ce) /* {{{ */ { zend_string *key; zend_function *parent_func; diff --git a/Zend/zend_inheritance.h b/Zend/zend_inheritance.h index 477874181e416..7171a9385f3ba 100644 --- a/Zend/zend_inheritance.h +++ b/Zend/zend_inheritance.h @@ -32,13 +32,13 @@ static zend_always_inline void zend_do_inheritance(zend_class_entry *ce, zend_cl zend_do_inheritance_ex(ce, parent_ce, 0); } -ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, zend_string *key); +ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, const zend_string *key); void zend_verify_abstract_class(zend_class_entry *ce); void zend_build_properties_info_table(zend_class_entry *ce); ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding); -void zend_inheritance_check_override(zend_class_entry *ce); +void zend_inheritance_check_override(const zend_class_entry *ce); ZEND_API extern zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces); ZEND_API extern zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies); @@ -53,7 +53,7 @@ typedef enum { ZEND_API zend_inheritance_status zend_verify_property_hook_variance(const zend_property_info *prop_info, const zend_function *func); ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error(const zend_property_info *prop_info); ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error_ex(zend_string *value_param_name, zend_string *class_name, zend_string *prop_name); -ZEND_API void zend_verify_hooked_property(zend_class_entry *ce, zend_property_info *prop_info, zend_string *prop_name); +ZEND_API void zend_verify_hooked_property(const zend_class_entry *ce, zend_property_info *prop_info, zend_string *prop_name); END_EXTERN_C() diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index c0127feabbf68..ce9cc00fdfb95 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -412,13 +412,12 @@ ZEND_API int zend_user_serialize(zval *object, unsigned char **buffer, size_t *b zend_call_method_with_0_params( Z_OBJ_P(object), Z_OBJCE_P(object), NULL, "serialize", &retval); - if (Z_TYPE(retval) == IS_UNDEF || EG(exception)) { + if (Z_TYPE(retval) == IS_UNDEF) { result = FAILURE; } else { switch(Z_TYPE(retval)) { case IS_NULL: /* we could also make this '*buf_len = 0' but this allows to skip variables */ - zval_ptr_dtor(&retval); return FAILURE; case IS_STRING: *buffer = (unsigned char*)estrndup(Z_STRVAL(retval), Z_STRLEN(retval)); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index c671b3a295e5c..190292fada760 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -217,6 +217,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %token T_OBJECT_CAST "'(object)'" %token T_BOOL_CAST "'(bool)'" %token T_UNSET_CAST "'(unset)'" +%token T_VOID_CAST "'(void)'" %token T_OBJECT_OPERATOR "'->'" %token T_NULLSAFE_OBJECT_OPERATOR "'?->'" %token T_DOUBLE_ARROW "'=>'" @@ -267,7 +268,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type callable_expr callable_variable static_member new_variable %type encaps_var encaps_var_offset isset_variables %type top_statement_list use_declarations const_list inner_statement_list if_stmt -%type alt_if_stmt for_exprs switch_case_list global_var_list static_var_list +%type alt_if_stmt for_cond_exprs for_exprs switch_case_list global_var_list static_var_list %type echo_expr_list unset_variables catch_name_list catch_list optional_variable parameter_list class_statement_list %type implements_list case_list if_stmt_without_else %type non_empty_parameter_list argument_list non_empty_argument_list property_list @@ -507,7 +508,7 @@ statement: { $$ = zend_ast_create(ZEND_AST_WHILE, $3, $5); } | T_DO statement T_WHILE '(' expr ')' ';' { $$ = zend_ast_create(ZEND_AST_DO_WHILE, $2, $5); } - | T_FOR '(' for_exprs ';' for_exprs ';' for_exprs ')' for_statement + | T_FOR '(' for_exprs ';' for_cond_exprs ';' for_exprs ')' for_statement { $$ = zend_ast_create(ZEND_AST_FOR, $3, $5, $7, $9); } | T_SWITCH '(' expr ')' switch_case_list { $$ = zend_ast_create(ZEND_AST_SWITCH, $3, $5); } @@ -534,6 +535,7 @@ statement: { $$ = zend_ast_create(ZEND_AST_TRY, $3, $5, $6); } | T_GOTO T_STRING ';' { $$ = zend_ast_create(ZEND_AST_GOTO, $2); } | T_STRING ':' { $$ = zend_ast_create(ZEND_AST_LABEL, $1); } + | T_VOID_CAST expr ';' { $$ = zend_ast_create(ZEND_AST_CAST_VOID, $2); } ; catch_list: @@ -1167,6 +1169,12 @@ echo_expr: expr { $$ = zend_ast_create(ZEND_AST_ECHO, $1); } ; +for_cond_exprs: + %empty { $$ = NULL; } + | non_empty_for_exprs ',' expr { $$ = zend_ast_list_add($1, $3); } + | expr { $$ = zend_ast_create_list(1, ZEND_AST_EXPR_LIST, $1); } +; + for_exprs: %empty { $$ = NULL; } | non_empty_for_exprs { $$ = $1; } @@ -1174,6 +1182,8 @@ for_exprs: non_empty_for_exprs: non_empty_for_exprs ',' expr { $$ = zend_ast_list_add($1, $3); } + | non_empty_for_exprs ',' T_VOID_CAST expr { $$ = zend_ast_list_add($1, zend_ast_create(ZEND_AST_CAST_VOID, $4)); } + | T_VOID_CAST expr { $$ = zend_ast_create_list(1, ZEND_AST_EXPR_LIST, zend_ast_create(ZEND_AST_CAST_VOID, $2)); } | expr { $$ = zend_ast_create_list(1, ZEND_AST_EXPR_LIST, $1); } ; @@ -1819,6 +1829,14 @@ static YYSIZE_T zend_yytnamerr(char *yyres, const char *yystr) return sizeof("\"\\\"")-1; } + /* We used "amp" as a dummy label to avoid a duplicate token literal warning. */ + if (strcmp(toktype, "\"amp\"") == 0) { + if (yyres) { + yystpcpy(yyres, "token \"&\""); + } + return sizeof("token \"&\"")-1; + } + /* Strip off the outer quote marks */ if (toktype_len >= 2 && *toktype == '"') { toktype++; diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 7ae73875926eb..4c883b81c5f7d 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -1657,6 +1657,10 @@ OPTIONAL_WHITESPACE_OR_COMMENTS ({WHITESPACE}|{MULTI_LINE_COMMENT}|{SINGLE_LINE_ RETURN_TOKEN(T_UNSET_CAST); } +"("{TABS_AND_SPACES}("void"){TABS_AND_SPACES}")" { + RETURN_TOKEN(T_VOID_CAST); +} + "eval" { RETURN_TOKEN_WITH_IDENT(T_EVAL); } diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 41ba3e1cd288d..d1b950160e1cc 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -268,14 +268,17 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, obj = zend_objects_new(reflection_ce); - for (int i = 0; i < obj->ce->default_properties_count; i++) { + /* Iterate in reverse to avoid overriding Z_PROP_FLAG_P() of child props with added hooks (GH-17870). */ + for (int i = obj->ce->default_properties_count - 1; i >= 0; i--) { zval *p = &obj->properties_table[i]; ZVAL_UNDEF(p); - if (EXPECTED(obj->ce->properties_info_table[i])) { + Z_PROP_FLAG_P(p) = 0; + + zend_property_info *prop_info = obj->ce->properties_info_table[i]; + if (prop_info) { + zval *p = &obj->properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]; Z_PROP_FLAG_P(p) = IS_PROP_UNINIT | IS_PROP_LAZY; lazy_properties_count++; - } else { - Z_PROP_FLAG_P(p) = 0; } } } else { @@ -326,7 +329,7 @@ ZEND_API zend_object *zend_object_make_lazy(zend_object *obj, for (int i = 0; i < reflection_ce->default_properties_count; i++) { zend_property_info *prop_info = obj->ce->properties_info_table[i]; if (EXPECTED(prop_info)) { - zval *p = &obj->properties_table[i]; + zval *p = &obj->properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]; if (Z_TYPE_P(p) != IS_UNDEF) { if ((prop_info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(p) & IS_PROP_REINITABLE) /* TODO: test final property */ @@ -408,12 +411,16 @@ static void zend_lazy_object_revert_init(zend_object *obj, zval *properties_tabl zval *properties_table = obj->properties_table; for (int i = 0; i < ce->default_properties_count; i++) { - zval *p = &properties_table[i]; + zend_property_info *prop_info = ce->properties_info_table[i]; + if (!prop_info) { + continue; + } + + zval *p = &properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]; zend_object_dtor_property(obj, p); - ZVAL_COPY_VALUE_PROP(p, &properties_table_snapshot[i]); + ZVAL_COPY_VALUE_PROP(p, &properties_table_snapshot[OBJ_PROP_TO_NUM(prop_info->offset)]); - zend_property_info *prop_info = ce->properties_info_table[i]; - if (Z_ISREF_P(p) && prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { + if (Z_ISREF_P(p) && ZEND_TYPE_IS_SET(prop_info->type)) { ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(p), prop_info); } } @@ -526,10 +533,12 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) obj->properties = NULL; for (int i = 0; i < Z_OBJ(retval)->ce->default_properties_count; i++) { - if (EXPECTED(Z_OBJ(retval)->ce->properties_info_table[i])) { - zend_object_dtor_property(obj, &obj->properties_table[i]); - ZVAL_UNDEF(&obj->properties_table[i]); - Z_PROP_FLAG_P(&obj->properties_table[i]) = IS_PROP_UNINIT | IS_PROP_LAZY; + zend_property_info *prop_info = Z_OBJ(retval)->ce->properties_info_table[i]; + if (EXPECTED(prop_info)) { + zval *prop = &obj->properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]; + zend_object_dtor_property(obj, prop); + ZVAL_UNDEF(prop); + Z_PROP_FLAG_P(prop) = IS_PROP_UNINIT | IS_PROP_LAZY; } } @@ -722,13 +731,16 @@ zend_object *zend_lazy_object_clone(zend_object *old_obj) zend_class_entry *ce = old_obj->ce; zend_object *new_proxy = zend_objects_new(ce); - for (int i = 0; i < ce->default_properties_count; i++) { + /* Iterate in reverse to avoid overriding Z_PROP_FLAG_P() of child props with added hooks (GH-17870). */ + for (int i = ce->default_properties_count - 1; i >= 0; i--) { zval *p = &new_proxy->properties_table[i]; ZVAL_UNDEF(p); - if (EXPECTED(ce->properties_info_table[i])) { + Z_PROP_FLAG_P(p) = 0; + + zend_property_info *prop_info = ce->properties_info_table[i]; + if (prop_info) { + zval *p = &new_proxy->properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]; Z_PROP_FLAG_P(p) = IS_PROP_UNINIT | IS_PROP_LAZY; - } else { - Z_PROP_FLAG_P(p) = 0; } } diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 56bea75922673..a31c7d2afdeee 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -673,9 +673,23 @@ static bool zend_is_in_hook(const zend_property_info *prop_info) static bool zend_should_call_hook(const zend_property_info *prop_info, const zend_object *obj) { - return !zend_is_in_hook(prop_info) - /* execute_data and This are guaranteed to be set if zend_is_in_hook() returns true. */ - || Z_OBJ(EG(current_execute_data)->This) != obj; + if (!zend_is_in_hook(prop_info)) { + return true; + } + + /* execute_data and This are guaranteed to be set if zend_is_in_hook() returns true. */ + zend_object *parent_obj = Z_OBJ(EG(current_execute_data)->This); + if (parent_obj == obj) { + return false; + } + + if (zend_object_is_lazy_proxy(parent_obj) + && zend_lazy_object_initialized(parent_obj) + && zend_lazy_object_get_instance(parent_obj) == obj) { + return false; + } + + return true; } static ZEND_COLD void zend_throw_no_prop_backing_value_access(zend_string *class_name, zend_string *prop_name, bool is_read) @@ -863,7 +877,6 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int if (!((*guard) & IN_ISSET)) { GC_ADDREF(zobj); - ZVAL_UNDEF(&tmp_result); *guard |= IN_ISSET; zend_std_call_issetter(zobj, name, &tmp_result); @@ -932,6 +945,18 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int goto exit; } + if (UNEXPECTED(guard)) { + uint32_t guard_type = (type == BP_VAR_IS) && zobj->ce->__isset + ? IN_ISSET : IN_GET; + guard = zend_get_property_guard(zobj, name); + if (!((*guard) & guard_type)) { + (*guard) |= guard_type; + retval = zend_std_read_property(zobj, name, type, cache_slot, rv); + (*guard) &= ~guard_type; + return retval; + } + } + return zend_std_read_property(zobj, name, type, cache_slot, rv); } } @@ -956,6 +981,43 @@ static zend_always_inline bool property_uses_strict_types(void) { && ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)); } +static zval *forward_write_to_lazy_object(zend_object *zobj, + zend_string *name, zval *value, void **cache_slot, bool guarded) +{ + zval *variable_ptr; + + /* backup value as it may change during initialization */ + zval backup; + ZVAL_COPY(&backup, value); + + zend_object *instance = zend_lazy_object_init(zobj); + if (UNEXPECTED(!instance)) { + zval_ptr_dtor(&backup); + return &EG(error_zval); + } + + if (UNEXPECTED(guarded)) { + uint32_t *guard = zend_get_property_guard(instance, name); + if (!((*guard) & IN_SET)) { + (*guard) |= IN_SET; + variable_ptr = zend_std_write_property(instance, name, &backup, cache_slot); + (*guard) &= ~IN_SET; + goto exit; + } + } + + variable_ptr = zend_std_write_property(instance, name, &backup, cache_slot); + +exit: + zval_ptr_dtor(&backup); + + if (variable_ptr == &backup) { + variable_ptr = value; + } + + return variable_ptr; +} + ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zval *value, void **cache_slot) /* {{{ */ { zval *variable_ptr, tmp; @@ -1137,7 +1199,8 @@ found:; variable_ptr = value; } else if (EXPECTED(!IS_WRONG_PROPERTY_OFFSET(property_offset))) { if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - goto lazy_init; + return forward_write_to_lazy_object(zobj, name, value, + cache_slot, /* guarded */ true); } goto write_std_property; @@ -1184,21 +1247,9 @@ found:; exit: return variable_ptr; -lazy_init:; - /* backup value as it may change during initialization */ - zval backup; - ZVAL_COPY(&backup, value); - - zobj = zend_lazy_object_init(zobj); - if (UNEXPECTED(!zobj)) { - variable_ptr = &EG(error_zval); - zval_ptr_dtor(&backup); - goto exit; - } - - variable_ptr = zend_std_write_property(zobj, name, &backup, cache_slot); - zval_ptr_dtor(&backup); - return variable_ptr; +lazy_init: + return forward_write_to_lazy_object(zobj, name, value, cache_slot, + /* guarded */ false); } /* }}} */ @@ -1519,6 +1570,17 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void if (!zobj) { return; } + + if (UNEXPECTED(guard)) { + guard = zend_get_property_guard(zobj, name); + if (!((*guard) & IN_UNSET)) { + (*guard) |= IN_UNSET; + zend_std_unset_property(zobj, name, cache_slot); + (*guard) &= ~IN_UNSET; + return; + } + } + zend_std_unset_property(zobj, name, cache_slot); return; } @@ -1617,7 +1679,7 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce func->fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_PUBLIC | ZEND_ACC_VARIADIC - | (fbc->common.fn_flags & (ZEND_ACC_RETURN_REFERENCE|ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)); + | (fbc->common.fn_flags & (ZEND_ACC_RETURN_REFERENCE|ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED|ZEND_ACC_NODISCARD)); /* Attributes outlive the trampoline because they are created by the compiler. */ func->attributes = fbc->common.attributes; if (is_static) { @@ -1712,6 +1774,9 @@ ZEND_API zend_function *zend_get_property_hook_trampoline( func = (zend_function *)(uintptr_t)ecalloc(1, sizeof(zend_internal_function)); } func->type = ZEND_INTERNAL_FUNCTION; + /* This trampoline does not use the call_trampoline_op, so it won't reuse the call frame, + * which means we don't even need to reserve a temporary for observers. */ + func->common.T = 0; func->common.arg_flags[0] = 0; func->common.arg_flags[1] = 0; func->common.arg_flags[2] = 0; @@ -2305,6 +2370,8 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has } (*guard) &= ~IN_ISSET; OBJ_RELEASE(zobj); + } else { + goto lazy_init; } } @@ -2320,6 +2387,16 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has goto exit; } + if (UNEXPECTED(zobj->ce->__isset)) { + uint32_t *guard = zend_get_property_guard(zobj, name); + if (!((*guard) & IN_ISSET)) { + (*guard) |= IN_ISSET; + result = zend_std_has_property(zobj, name, has_set_exists, cache_slot); + (*guard) &= ~IN_ISSET; + return result; + } + } + return zend_std_has_property(zobj, name, has_set_exists, cache_slot); } } @@ -2374,17 +2451,9 @@ ZEND_API zend_result zend_std_get_closure(zend_object *obj, zend_class_entry **c return FAILURE; } *fptr_ptr = Z_FUNC_P(func); - *ce_ptr = ce; - if ((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC) { - if (obj_ptr) { - *obj_ptr = NULL; - } - } else { - if (obj_ptr) { - *obj_ptr = obj; - } - } + *obj_ptr = obj; + return SUCCESS; } /* }}} */ diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c index 1ba250bec6439..9b1b6dd4fcbb4 100644 --- a/Zend/zend_objects_API.c +++ b/Zend/zend_objects_API.c @@ -203,7 +203,7 @@ ZEND_API void ZEND_FASTCALL zend_objects_store_del(zend_object *object) /* {{{ * ZEND_API ZEND_COLD zend_property_info *zend_get_property_info_for_slot_slow(zend_object *obj, zval *slot) { - uintptr_t offset = (uintptr_t)slot - (uintptr_t)obj->properties_table; + uintptr_t offset = OBJ_PROP_SLOT_TO_OFFSET(obj, slot); zend_property_info *prop_info; ZEND_HASH_MAP_FOREACH_PTR(&obj->ce->properties_info, prop_info) { if (prop_info->offset == offset) { diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 12c2759656b2d..b25152ec1248b 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -112,7 +112,7 @@ ZEND_API void destroy_zend_function(zend_function *function) ZEND_API void zend_type_release(zend_type type, bool persistent) { if (ZEND_TYPE_HAS_LIST(type)) { zend_type *list_type; - ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) { + ZEND_TYPE_LIST_FOREACH_MUTABLE(ZEND_TYPE_LIST(type), list_type) { zend_type_release(*list_type, persistent); } ZEND_TYPE_LIST_FOREACH_END(); if (!ZEND_TYPE_USES_ARENA(type)) { @@ -636,13 +636,6 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) } if (op_array->num_dynamic_func_defs) { for (i = 0; i < op_array->num_dynamic_func_defs; i++) { - /* Closures overwrite static_variables in their copy. - * Make sure to destroy them when the prototype function is destroyed. */ - if (op_array->dynamic_func_defs[i]->static_variables - && (op_array->dynamic_func_defs[i]->fn_flags & ZEND_ACC_CLOSURE)) { - zend_array_destroy(op_array->dynamic_func_defs[i]->static_variables); - op_array->dynamic_func_defs[i]->static_variables = NULL; - } destroy_op_array(op_array->dynamic_func_defs[i]); } efree(op_array->dynamic_func_defs); @@ -940,6 +933,14 @@ static void zend_calc_live_ranges( opnum--; opline--; + /* SEPARATE always redeclares its op1. For the purposes of live-ranges, + * its declaration is irrelevant. Don't terminate the current live-range + * to avoid breaking special handling of COPY_TMP. */ + if (opline->opcode == ZEND_SEPARATE) { + ZEND_ASSERT(opline->op1.var == opline->result.var); + continue; + } + if ((opline->result_type & (IS_TMP_VAR|IS_VAR)) && !is_fake_def(opline)) { uint32_t var_num = EX_VAR_TO_NUM(opline->result.var) - var_offset; /* Defs without uses can occur for two reasons: Either because the result is diff --git a/Zend/zend_smart_str.c b/Zend/zend_smart_str.c index ade137a4bb6c3..501f6e6176c8b 100644 --- a/Zend/zend_smart_str.c +++ b/Zend/zend_smart_str.c @@ -131,6 +131,13 @@ ZEND_API void smart_str_append_printf(smart_str *dest, const char *format, ...) va_end(arg); } +ZEND_API void smart_string_append_printf(smart_string *dest, const char *format, ...) { + va_list arg; + va_start(arg, format); + zend_printf_to_smart_string(dest, format, arg); + va_end(arg); +} + #define SMART_STRING_OVERHEAD (ZEND_MM_OVERHEAD + 1) #define SMART_STRING_START_SIZE 256 #define SMART_STRING_START_LEN (SMART_STRING_START_SIZE - SMART_STRING_OVERHEAD) diff --git a/Zend/zend_smart_string.h b/Zend/zend_smart_string.h index 8149b29fb3330..9f04e1a340ad2 100644 --- a/Zend/zend_smart_string.h +++ b/Zend/zend_smart_string.h @@ -48,6 +48,9 @@ #define smart_string_append_unsigned(str, val) \ smart_string_append_unsigned_ex((str), (val), 0) +ZEND_API void smart_string_append_printf(smart_string *dest, const char *format, ...) + ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); + ZEND_API void ZEND_FASTCALL _smart_string_alloc_persistent(smart_string *str, size_t len); ZEND_API void ZEND_FASTCALL _smart_string_alloc(smart_string *str, size_t len); diff --git a/Zend/zend_types.h b/Zend/zend_types.h index f839cec3b3667..7676a1d42a5f4 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -209,8 +209,14 @@ typedef struct { /* This iterates over a zend_type_list. */ #define ZEND_TYPE_LIST_FOREACH(list, type_ptr) do { \ + const zend_type *_list = (list)->types; \ + const zend_type *_end = _list + (list)->num_types; \ + for (; _list < _end; _list++) { \ + type_ptr = _list; + +#define ZEND_TYPE_LIST_FOREACH_MUTABLE(list, type_ptr) do { \ zend_type *_list = (list)->types; \ - zend_type *_end = _list + (list)->num_types; \ + const zend_type *_end = _list + (list)->num_types; \ for (; _list < _end; _list++) { \ type_ptr = _list; @@ -221,7 +227,22 @@ typedef struct { /* This iterates over any zend_type. If it's a type list, all list elements will * be visited. If it's a single type, only the single type is visited. */ #define ZEND_TYPE_FOREACH(type, type_ptr) do { \ - zend_type *_cur, *_end; \ + const zend_type *_cur, *_end; \ + if (ZEND_TYPE_HAS_LIST(type)) { \ + zend_type_list *_list = ZEND_TYPE_LIST(type); \ + _cur = _list->types; \ + _end = _cur + _list->num_types; \ + } else { \ + _cur = &(type); \ + _end = _cur + 1; \ + } \ + do { \ + type_ptr = _cur; + + +#define ZEND_TYPE_FOREACH_MUTABLE(type, type_ptr) do { \ + zend_type *_cur; \ + const zend_type *_end; \ if (ZEND_TYPE_HAS_LIST(type)) { \ zend_type_list *_list = ZEND_TYPE_LIST(type); \ _cur = _list->types; \ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 7e471b5acd8b6..7b861688c9661 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1116,6 +1116,14 @@ ZEND_VM_HANDLER(29, ZEND_ASSIGN_STATIC_PROP_OP, ANY, ANY, OP) HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + FREE_OP_DATA(); + HANDLE_EXCEPTION(); + } + value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); do { @@ -1430,6 +1438,13 @@ ZEND_VM_HANDLER(38, ZEND_PRE_INC_STATIC_PROP, ANY, ANY, CACHE_SLOT) HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + zend_pre_incdec_property_zval(prop, ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); @@ -1457,6 +1472,13 @@ ZEND_VM_HANDLER(40, ZEND_POST_INC_STATIC_PROP, ANY, ANY, CACHE_SLOT) HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + zend_post_incdec_property_zval(prop, ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); @@ -1836,18 +1858,29 @@ ZEND_VM_INLINE_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type) { USE_OPLINE zval *prop; + zend_property_info *prop_info; SAVE_OPLINE(); prop = zend_fetch_static_property_address( - NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, + &prop_info, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, type == BP_VAR_W ? opline->extended_value : 0 OPLINE_CC EXECUTE_DATA_CC); if (UNEXPECTED(!prop)) { ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS)); prop = &EG(uninitialized_zval); + } else if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + if (Z_TYPE_P(prop) == IS_OBJECT) { + ZEND_VM_C_GOTO(copy_deref); + } else if (type != BP_VAR_UNSET || Z_TYPE_P(prop) != IS_UNDEF) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + } + prop = &EG(uninitialized_zval); } if (type == BP_VAR_R || type == BP_VAR_IS) { +ZEND_VM_C_LABEL(copy_deref): ZVAL_COPY_DEREF(EX_VAR(opline->result.var), prop); } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), prop); @@ -2457,12 +2490,14 @@ ZEND_VM_C_LABEL(assign_object): void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +ZEND_VM_C_LABEL(assign_obj_simple): property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); ZEND_VM_C_GOTO(free_and_exit_assign_obj); @@ -2534,14 +2569,12 @@ ZEND_VM_C_LABEL(fast_assign_obj): } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - ZEND_VM_C_GOTO(free_and_exit_assign_obj); - } else { - ZEND_VM_C_GOTO(fast_assign_obj); + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + ZEND_VM_C_GOTO(assign_obj_simple); } /* Fall through to write_property for hooks. */ } @@ -2893,6 +2926,14 @@ ZEND_VM_HANDLER(33, ZEND_ASSIGN_STATIC_PROP_REF, ANY, ANY, CACHE_SLOT|SRC) HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + FREE_OP_DATA(); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + value_ptr = GET_OP_DATA_ZVAL_PTR_PTR(BP_VAR_W); if (OP_DATA_TYPE == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION) && UNEXPECTED(!Z_ISREF_P(value_ptr))) { @@ -3207,7 +3248,7 @@ ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY) USE_OPLINE SAVE_OPLINE(); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -4156,8 +4197,15 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER)) SAVE_OPLINE(); EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_deprecated_function(fbc); + const uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD; + + if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) { + if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) { + zend_deprecated_function(fbc); + } + if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) { + zend_nodiscard_function(fbc); + } if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); if (!RETURN_VALUE_USED(opline)) { @@ -4260,8 +4308,15 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER)) SAVE_OPLINE(); EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_deprecated_function(fbc); + const uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD; + + if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) { + if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) { + zend_deprecated_function(fbc); + } + if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) { + zend_nodiscard_function(fbc); + } if (UNEXPECTED(EG(exception) != NULL)) { if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); @@ -4368,7 +4423,7 @@ ZEND_VM_C_LABEL(fcall_end): ZEND_VM_CONTINUE(); } -ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED|CACHE_SLOT) +ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED) { if (OP1_TYPE == IS_UNUSED) { SAVE_OPLINE(); @@ -4410,7 +4465,6 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV } zend_reference *ref = NULL; - void *cache_slot = CACHE_ADDR(opline->op2.num); if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { ref = Z_REF_P(retval_ref); @@ -4427,7 +4481,7 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } @@ -5602,11 +5656,10 @@ ZEND_VM_HOT_HANDLER(199, ZEND_CHECK_UNDEF_ARGS, UNUSED, UNUSED) ZEND_VM_COLD_HELPER(zend_missing_arg_helper, ANY, ANY) { -#ifdef ZEND_VM_IP_GLOBAL_REG USE_OPLINE SAVE_OPLINE(); -#endif + zend_missing_arg_error(execute_data); HANDLE_EXCEPTION(); } @@ -5616,14 +5669,14 @@ ZEND_VM_HELPER(zend_verify_recv_arg_type_helper, ANY, ANY, zval *op_1) USE_OPLINE SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), opline->op1.num, op_1, CACHE_ADDR(opline->extended_value)))) { + if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), opline->op1.num, op_1))) { HANDLE_EXCEPTION(); } ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_HANDLER(63, ZEND_RECV, NUM, UNUSED, CACHE_SLOT) +ZEND_VM_HOT_HANDLER(63, ZEND_RECV, NUM, UNUSED) { USE_OPLINE uint32_t arg_num = opline->op1.num; @@ -5642,7 +5695,7 @@ ZEND_VM_HOT_HANDLER(63, ZEND_RECV, NUM, UNUSED, CACHE_SLOT) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_RECV, op->op2.num == MAY_BE_ANY, ZEND_RECV_NOTYPE, NUM, NUM, CACHE_SLOT) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_RECV, op->op2.num == MAY_BE_ANY, ZEND_RECV_NOTYPE, NUM, NUM) { USE_OPLINE uint32_t arg_num = opline->op1.num; @@ -5654,7 +5707,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_RECV, op->op2.num == MAY_BE_ANY, ZEND_RECV_NO ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST, CACHE_SLOT) +ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST) { USE_OPLINE uint32_t arg_num; @@ -5694,7 +5747,7 @@ ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST, CACHE_SLOT) ZEND_VM_C_LABEL(recv_init_check_type): if ((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) { SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->extended_value)))) { + if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param))) { HANDLE_EXCEPTION(); } } @@ -5704,7 +5757,7 @@ ZEND_VM_C_LABEL(recv_init_check_type): ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, UNUSED, CACHE_SLOT) +ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, UNUSED) { USE_OPLINE uint32_t arg_num = opline->op1.num; @@ -5727,7 +5780,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, UNUSED, CACHE_SLOT) if (ZEND_TYPE_IS_SET(arg_info->type)) { ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS); do { - if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param, CACHE_ADDR(opline->extended_value)))) { + if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param))) { ZEND_HASH_FILL_FINISH(); HANDLE_EXCEPTION(); } @@ -5755,7 +5808,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, UNUSED, CACHE_SLOT) if (ZEND_TYPE_IS_SET(arg_info->type)) { SEPARATE_ARRAY(params); ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(EX(extra_named_params), name, param) { - if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param, CACHE_ADDR(opline->extended_value)))) { + if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param))) { HANDLE_EXCEPTION(); } Z_TRY_ADDREF_P(param); @@ -6103,8 +6156,10 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO } bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; - if (UNEXPECTED(is_constant_deprecated)) { + if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { + CONST_PROTECT_RECURSION(c); zend_deprecated_class_constant(c, constant_name); + CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -6403,7 +6458,6 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) USE_OPLINE zval *expr; zval *result = EX_VAR(opline->result.var); - HashTable *ht; SAVE_OPLINE(); expr = GET_OP1_ZVAL_PTR(BP_VAR_R); @@ -6437,53 +6491,10 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) } if (opline->extended_value == IS_ARRAY) { - if (OP1_TYPE == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { - if (Z_TYPE_P(expr) != IS_NULL) { - ZVAL_ARR(result, zend_new_array(1)); - expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); - if (OP1_TYPE == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } else { - ZVAL_EMPTY_ARRAY(result); - } - } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { - /* Optimized version without rebuilding properties HashTable */ - ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); - } else { - HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); - if (obj_ht) { - /* fast copy */ - ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, - (Z_OBJCE_P(expr)->default_properties_count || - Z_OBJ_P(expr)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht)))); - zend_release_properties(obj_ht); - } else { - ZVAL_EMPTY_ARRAY(result); - } - } + zend_cast_zval_to_array(result, expr, OP1_TYPE); } else { ZEND_ASSERT(opline->extended_value == IS_OBJECT); - ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); - if (Z_TYPE_P(expr) == IS_ARRAY) { - ht = zend_symtable_to_proptable(Z_ARR_P(expr)); - if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { - /* TODO: try not to duplicate immutable arrays as well ??? */ - ht = zend_array_dup(ht); - } - Z_OBJ_P(result)->properties = ht; - } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); - expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); - if (OP1_TYPE == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } + zend_cast_zval_to_object(result, expr, OP1_TYPE); } } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 9209399a5cdbf..2211f6753485d 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -306,6 +306,8 @@ static uint8_t zend_user_opcodes[256] = {0, 241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 }; +#include "Zend/zend_vm_opcodes.h" + #define SPEC_START_MASK 0x0000ffff #define SPEC_EXTRA_MASK 0xfffc0000 #define SPEC_RULE_OP1 0x00010000 @@ -367,13 +369,13 @@ static const void *zend_vm_get_opcode_handler_func(uint8_t opcode, const zend_op #ifdef ZEND_VM_FP_GLOBAL_REG # define ZEND_OPCODE_HANDLER_ARGS void # define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU -# define ZEND_OPCODE_HANDLER_ARGS_DC -# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC +# define ZEND_OPCODE_HANDLER_ARGS_EX +# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX #else -# define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data -# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data -# define ZEND_OPCODE_HANDLER_ARGS_DC , ZEND_OPCODE_HANDLER_ARGS -# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC , ZEND_OPCODE_HANDLER_ARGS_PASSTHRU +# define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data, const zend_op *opline +# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data, opline +# define ZEND_OPCODE_HANDLER_ARGS_EX ZEND_OPCODE_HANDLER_ARGS, +# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX ZEND_OPCODE_HANDLER_ARGS_PASSTHRU, #endif #if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG) @@ -394,18 +396,18 @@ static const void *zend_vm_get_opcode_handler_func(uint8_t opcode, const zend_op # define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE # endif #else -# define ZEND_OPCODE_HANDLER_RET int +# define ZEND_OPCODE_HANDLER_RET const zend_op * # define ZEND_VM_TAIL_CALL(call) return call -# define ZEND_VM_CONTINUE() return 0 -# define ZEND_VM_RETURN() return -1 +# define ZEND_VM_CONTINUE() return opline +# define ZEND_VM_RETURN() return (const zend_op*)ZEND_VM_ENTER_BIT # define ZEND_VM_HOT # define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE #endif typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS); -#define DCL_OPLINE #ifdef ZEND_VM_IP_GLOBAL_REG +# define DCL_OPLINE # define OPLINE opline # define USE_OPLINE # define LOAD_OPLINE() opline = EX(opline) @@ -414,12 +416,13 @@ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_H # define SAVE_OPLINE() EX(opline) = opline # define SAVE_OPLINE_EX() SAVE_OPLINE() #else -# define OPLINE EX(opline) -# define USE_OPLINE const zend_op *opline = EX(opline); -# define LOAD_OPLINE() -# define LOAD_OPLINE_EX() -# define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE() -# define SAVE_OPLINE() +# define DCL_OPLINE const zend_op *opline; +# define OPLINE opline +# define USE_OPLINE +# define LOAD_OPLINE() opline = EX(opline) +# define LOAD_OPLINE_EX() opline = EX(opline) +# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1 +# define SAVE_OPLINE() EX(opline) = opline # define SAVE_OPLINE_EX() #endif #define HANDLE_EXCEPTION() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_CONTINUE() @@ -433,9 +436,10 @@ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_H # define ZEND_VM_ENTER() opline = EG(current_execute_data)->opline; ZEND_VM_ENTER_EX() # define ZEND_VM_LEAVE() return 2 #else -# define ZEND_VM_ENTER_EX() return 1 -# define ZEND_VM_ENTER() return 1 -# define ZEND_VM_LEAVE() return 2 +# define ZEND_VM_ENTER_BIT 1ULL +# define ZEND_VM_ENTER_EX() return (zend_op*)((uintptr_t)opline | ZEND_VM_ENTER_BIT) +# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX() +# define ZEND_VM_LEAVE() return (zend_op*)((uintptr_t)opline | ZEND_VM_ENTER_BIT) #endif #define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); #define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -444,7 +448,7 @@ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_H static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS); static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS); -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_add_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_add_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { USE_OPLINE @@ -465,7 +469,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_add_helper_S ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_sub_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_sub_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { USE_OPLINE @@ -486,7 +490,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_sub_helper_S ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_mul_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_mul_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { USE_OPLINE @@ -517,7 +521,7 @@ static zend_never_inline ZEND_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_mo HANDLE_EXCEPTION(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_mod_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_mod_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { USE_OPLINE @@ -538,7 +542,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_mod_helper_S ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_shift_left_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_shift_left_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { USE_OPLINE @@ -559,7 +563,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_shift_left_h ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_shift_right_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_shift_right_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { USE_OPLINE @@ -580,7 +584,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_shift_right_ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_equal_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { int ret; USE_OPLINE @@ -602,7 +606,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_equal_hel ZEND_VM_SMART_BRANCH(ret == 0, 1); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_not_equal_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { int ret; USE_OPLINE @@ -624,7 +628,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_not_equal ZEND_VM_SMART_BRANCH(ret != 0, 1); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { int ret; USE_OPLINE @@ -646,7 +650,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_h ZEND_VM_SMART_BRANCH(ret < 0, 1); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_or_equal_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_or_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { int ret; USE_OPLINE @@ -668,7 +672,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_o ZEND_VM_SMART_BRANCH(ret <= 0, 1); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_bw_or_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_bw_or_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { USE_OPLINE @@ -689,7 +693,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_bw_or_helper ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_bw_and_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_bw_and_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { USE_OPLINE @@ -710,7 +714,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_bw_and_helpe ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_bw_xor_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_bw_xor_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { USE_OPLINE @@ -731,7 +735,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_bw_xor_helpe ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_bw_not_helper_SPEC(zval *op_1 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_bw_not_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1) { USE_OPLINE @@ -783,6 +787,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_OP_SPEC_HAN HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); + HANDLE_EXCEPTION(); + } + value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1); do { @@ -826,6 +838,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_STATIC_PROP_SPEC_HANDL HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + zend_pre_incdec_property_zval(prop, ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); @@ -847,6 +866,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_INC_STATIC_PROP_SPEC_HAND HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + zend_post_incdec_property_zval(prop, ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); @@ -854,22 +880,33 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_INC_STATIC_PROP_SPEC_HAND } /* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */ -static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_static_prop_helper_SPEC(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_static_prop_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX int type) { USE_OPLINE zval *prop; + zend_property_info *prop_info; SAVE_OPLINE(); prop = zend_fetch_static_property_address( - NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, + &prop_info, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, type == BP_VAR_W ? opline->extended_value : 0 OPLINE_CC EXECUTE_DATA_CC); if (UNEXPECTED(!prop)) { ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS)); prop = &EG(uninitialized_zval); + } else if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + if (Z_TYPE_P(prop) == IS_OBJECT) { + goto copy_deref; + } else if (type != BP_VAR_UNSET || Z_TYPE_P(prop) != IS_UNDEF) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + } + prop = &EG(uninitialized_zval); } if (type == BP_VAR_R || type == BP_VAR_IS) { +copy_deref: ZVAL_COPY_DEREF(EX_VAR(opline->result.var), prop); } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), prop); @@ -880,19 +917,19 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_static_prop_helper_ /* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_R_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_R)); } /* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_W_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_W)); } /* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_RW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_RW)); } /* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ @@ -908,13 +945,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_FUNC_ARG_SPE /* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_UNSET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_UNSET)); } /* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_IS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_IS)); } static zend_never_inline ZEND_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_use_tmp_in_write_context_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) @@ -1105,6 +1142,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_REF_SPEC_HA HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + value_ptr = get_zval_ptr_ptr((opline+1)->op1_type, (opline+1)->op1, BP_VAR_W); if ((opline+1)->op1_type == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION) && UNEXPECTED(!Z_ISREF_P(value_ptr))) { @@ -1552,8 +1597,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S SAVE_OPLINE(); EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_deprecated_function(fbc); + const uint32_t no_discard = 0 ? 0 : ZEND_ACC_NODISCARD; + + if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) { + if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) { + zend_deprecated_function(fbc); + } + if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) { + zend_nodiscard_function(fbc); + } if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); if (!0) { @@ -1654,8 +1706,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S SAVE_OPLINE(); EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_deprecated_function(fbc); + const uint32_t no_discard = 1 ? 0 : ZEND_ACC_NODISCARD; + + if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) { + if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) { + zend_deprecated_function(fbc); + } + if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) { + zend_nodiscard_function(fbc); + } if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); if (!1) { @@ -1756,8 +1815,15 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_ SAVE_OPLINE(); EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_deprecated_function(fbc); + const uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD; + + if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) { + if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) { + zend_deprecated_function(fbc); + } + if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) { + zend_nodiscard_function(fbc); + } if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); if (!RETURN_VALUE_USED(opline)) { @@ -1860,8 +1926,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV SAVE_OPLINE(); EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_deprecated_function(fbc); + const uint32_t no_discard = 0 ? 0 : ZEND_ACC_NODISCARD; + + if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) { + if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) { + zend_deprecated_function(fbc); + } + if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) { + zend_nodiscard_function(fbc); + } if (UNEXPECTED(EG(exception) != NULL)) { if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); @@ -1978,8 +2051,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV SAVE_OPLINE(); EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_deprecated_function(fbc); + const uint32_t no_discard = 1 ? 0 : ZEND_ACC_NODISCARD; + + if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) { + if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) { + zend_deprecated_function(fbc); + } + if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) { + zend_nodiscard_function(fbc); + } if (UNEXPECTED(EG(exception) != NULL)) { if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); @@ -2096,8 +2176,15 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS SAVE_OPLINE(); EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_deprecated_function(fbc); + const uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD; + + if (UNEXPECTED(fbc->common.fn_flags & (ZEND_ACC_DEPRECATED|no_discard))) { + if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) { + zend_deprecated_function(fbc); + } + if ((fbc->common.fn_flags & no_discard) && EG(exception) == NULL) { + zend_nodiscard_function(fbc); + } if (UNEXPECTED(EG(exception) != NULL)) { if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); @@ -2282,7 +2369,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GENERATOR_CREATE_SPEC_HANDLER( } } -static zend_never_inline ZEND_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_cannot_pass_by_ref_helper_SPEC(uint32_t _arg_num, zval *_arg ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_cannot_pass_by_ref_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX uint32_t _arg_num, zval *_arg) { USE_OPLINE @@ -2660,21 +2747,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_O static zend_never_inline ZEND_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_missing_arg_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) { -#ifdef ZEND_VM_IP_GLOBAL_REG USE_OPLINE SAVE_OPLINE(); -#endif + zend_missing_arg_error(execute_data); HANDLE_EXCEPTION(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_verify_recv_arg_type_helper_SPEC(zval *op_1 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_verify_recv_arg_type_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1) { USE_OPLINE SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), opline->op1.num, op_1, CACHE_ADDR(opline->extended_value)))) { + if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), opline->op1.num, op_1))) { HANDLE_EXCEPTION(); } @@ -2693,7 +2779,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_NOTYPE_SPEC_H ZEND_VM_NEXT_OPCODE(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_case_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_case_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { int ret; USE_OPLINE @@ -3173,7 +3259,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NOP_SPEC_HANDLER(Z ZEND_VM_NEXT_OPCODE(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_dispatch_try_catch_finally_helper_SPEC(uint32_t try_catch_offset, uint32_t op_num ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_dispatch_try_catch_finally_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX uint32_t try_catch_offset, uint32_t op_num) { /* May be NULL during generator closing (only finally blocks are executed) */ zend_object *ex = EG(exception); @@ -3256,7 +3342,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER( /* Exception was thrown before executing any op */ if (UNEXPECTED(!throw_op)) { - ZEND_VM_TAIL_CALL(zend_dispatch_try_catch_finally_helper_SPEC(-1, 0 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_dispatch_try_catch_finally_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX -1, 0)); } uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes; @@ -3320,7 +3406,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER( } } - ZEND_VM_TAIL_CALL(zend_dispatch_try_catch_finally_helper_SPEC(current_try_catch_offset, throw_op_num ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_dispatch_try_catch_finally_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX current_try_catch_offset, throw_op_num)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -3419,7 +3505,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPC Z_OBJ_P(fast_call) = NULL; current_try_catch_offset = opline->op2.num; current_op_num = opline - EX(func)->op_array.opcodes; - ZEND_VM_TAIL_CALL(zend_dispatch_try_catch_finally_helper_SPEC(current_try_catch_offset, current_op_num ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_dispatch_try_catch_finally_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX current_try_catch_offset, current_op_num)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSERT_CHECK_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -4107,7 +4193,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CON recv_init_check_type: if ((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) { SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->extended_value)))) { + if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param))) { HANDLE_EXCEPTION(); } } @@ -4183,7 +4269,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_SPEC_UNUSED_H param = EX_VAR(opline->result.var); if (UNEXPECTED(!(opline->op2.num & (1u << Z_TYPE_P(param))))) { - ZEND_VM_TAIL_CALL(zend_verify_recv_arg_type_helper_SPEC(param ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_verify_recv_arg_type_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX param)); } ZEND_VM_NEXT_OPCODE(); @@ -4212,7 +4298,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_UNUSED_HAND if (ZEND_TYPE_IS_SET(arg_info->type)) { ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS); do { - if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param, CACHE_ADDR(opline->extended_value)))) { + if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param))) { ZEND_HASH_FILL_FINISH(); HANDLE_EXCEPTION(); } @@ -4240,7 +4326,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_UNUSED_HAND if (ZEND_TYPE_IS_SET(arg_info->type)) { SEPARATE_ARRAY(params); ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(EX(extra_named_params), name, param) { - if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param, CACHE_ADDR(opline->extended_value)))) { + if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param))) { HANDLE_EXCEPTION(); } Z_TRY_ADDREF_P(param); @@ -4377,7 +4463,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_NOT_SPEC_CONST ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_bw_not_helper_SPEC(op1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_bw_not_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BOOL_NOT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -5150,7 +5236,6 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H USE_OPLINE zval *expr; zval *result = EX_VAR(opline->result.var); - HashTable *ht; SAVE_OPLINE(); expr = RT_CONSTANT(opline, opline->op1); @@ -5183,53 +5268,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H } if (opline->extended_value == IS_ARRAY) { - if (IS_CONST == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { - if (Z_TYPE_P(expr) != IS_NULL) { - ZVAL_ARR(result, zend_new_array(1)); - expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); - if (IS_CONST == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } else { - ZVAL_EMPTY_ARRAY(result); - } - } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { - /* Optimized version without rebuilding properties HashTable */ - ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); - } else { - HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); - if (obj_ht) { - /* fast copy */ - ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, - (Z_OBJCE_P(expr)->default_properties_count || - Z_OBJ_P(expr)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht)))); - zend_release_properties(obj_ht); - } else { - ZVAL_EMPTY_ARRAY(result); - } - } + zend_cast_zval_to_array(result, expr, IS_CONST); } else { ZEND_ASSERT(opline->extended_value == IS_OBJECT); - ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); - if (Z_TYPE_P(expr) == IS_ARRAY) { - ht = zend_symtable_to_proptable(Z_ARR_P(expr)); - if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { - /* TODO: try not to duplicate immutable arrays as well ??? */ - ht = zend_array_dup(ht); - } - Z_OBJ_P(result)->properties = ht; - } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); - expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); - if (IS_CONST == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } + zend_cast_zval_to_object(result, expr, IS_CONST); } } @@ -6073,7 +6115,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SIMPLE arg = ZEND_CALL_VAR(EX(call), opline->result.var); if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(arg_num, arg ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX arg_num, arg)); } value = RT_CONSTANT(opline, opline->op1); ZVAL_COPY_VALUE(arg, value); @@ -6115,7 +6157,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CONST_CO } } - ZEND_VM_TAIL_CALL(zend_add_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_add_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6153,7 +6195,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CONST_CO } } - ZEND_VM_TAIL_CALL(zend_sub_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_sub_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6194,7 +6236,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_CONST_CO } } - ZEND_VM_TAIL_CALL(zend_mul_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_mul_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DIV_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6235,7 +6277,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_CONST_CO } } - ZEND_VM_TAIL_CALL(zend_mod_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_mod_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6256,7 +6298,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SL_SPEC_CONST_CON ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_shift_left_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_shift_left_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6275,7 +6317,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SR_SPEC_CONST_CON ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_shift_right_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_shift_right_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POW_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6377,7 +6419,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CON } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6435,7 +6477,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6478,7 +6520,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_C goto is_smaller_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6525,7 +6567,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQU goto is_smaller_or_equal_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SPACESHIP_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6557,7 +6599,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_OR_SPEC_CONST_ ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_bw_or_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_bw_or_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_AND_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6575,7 +6617,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_AND_SPEC_CONST ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_bw_and_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_bw_and_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_XOR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6593,7 +6635,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_XOR_SPEC_CONST ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_bw_xor_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_bw_xor_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BOOL_XOR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -7532,7 +7574,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_CONST_CONST_H } } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { send_val_by_ref: - ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(arg_num, arg ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX arg_num, arg)); } value = RT_CONSTANT(opline, opline->op1); ZVAL_COPY_VALUE(arg, value); @@ -7626,8 +7668,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS } bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; - if (UNEXPECTED(is_constant_deprecated)) { + if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { + CONST_PROTECT_RECURSION(c); zend_deprecated_class_constant(c, constant_name); + CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -8326,7 +8370,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CONST_TMP } } - ZEND_VM_TAIL_CALL(zend_add_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_add_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8364,7 +8408,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CONST_TMP } } - ZEND_VM_TAIL_CALL(zend_sub_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_sub_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8391,7 +8435,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_CONST_TMPVARCV_HANDLE } } - ZEND_VM_TAIL_CALL(zend_mod_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_mod_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SL_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8412,7 +8456,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SL_SPEC_CONST_TMPVARCV_HANDLER ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_shift_left_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_shift_left_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SR_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8431,7 +8475,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SR_SPEC_CONST_TMPVARCV_HANDLER ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_shift_right_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_shift_right_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8474,7 +8518,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CONST_TMPVARCV goto is_smaller_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CONST_TMPVARCV_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8517,7 +8561,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CO goto is_smaller_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CONST_TMPVARCV_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8560,7 +8604,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_CO goto is_smaller_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8607,7 +8651,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_CONST goto is_smaller_or_equal_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_CONST_TMPVARCV_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8654,7 +8698,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUA goto is_smaller_or_equal_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_CONST_TMPVARCV_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8701,7 +8745,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUA goto is_smaller_or_equal_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8786,8 +8830,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS } bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; - if (UNEXPECTED(is_constant_deprecated)) { + if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { + CONST_PROTECT_RECURSION(c); zend_deprecated_class_constant(c, constant_name); + CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -10453,7 +10499,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMPVAR_HANDLE ZEND_VM_RETURN(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_UNUSED(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_UNUSED(ZEND_OPCODE_HANDLER_ARGS_EX int type) { USE_OPLINE zval *varname; @@ -10556,17 +10602,17 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_R_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_R)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_W_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_W)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_RW_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_RW)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -10574,17 +10620,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_UNUS int fetch_type = (UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) ? BP_VAR_W : BP_VAR_R; - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(fetch_type ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX fetch_type)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_UNSET)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_IS_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_IS)); } /* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */ @@ -10782,7 +10828,6 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYP } zend_reference *ref = NULL; - void *cache_slot = CACHE_ADDR(opline->op2.num); if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { ref = Z_REF_P(retval_ref); @@ -10799,7 +10844,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYP } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } @@ -10861,7 +10906,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_CONST_UNUSED_ } } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { send_val_by_ref: - ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(arg_num, arg ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX arg_num, arg)); } value = RT_CONSTANT(opline, opline->op1); ZVAL_COPY_VALUE(arg, value); @@ -10898,7 +10943,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_C } } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { send_val_by_ref: - ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(arg_num, arg ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX arg_num, arg)); } value = RT_CONSTANT(opline, opline->op1); ZVAL_COPY_VALUE(arg, value); @@ -12953,7 +12998,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_NOT_SPEC_TMPVAR ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_bw_not_helper_SPEC(op1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_bw_not_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13021,7 +13066,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_TMPVARCV_ } } - ZEND_VM_TAIL_CALL(zend_add_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_add_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_TMPVARCV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13059,7 +13104,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_TMPVARCV_ } } - ZEND_VM_TAIL_CALL(zend_sub_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_sub_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_TMPVARCV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13100,7 +13145,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_TMPVARCV_CONST_HANDLE } } - ZEND_VM_TAIL_CALL(zend_mul_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_mul_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_TMPVARCV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13127,7 +13172,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_TMPVARCV_CONST_HANDLE } } - ZEND_VM_TAIL_CALL(zend_mod_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_mod_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SL_SPEC_TMPVARCV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13148,7 +13193,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SL_SPEC_TMPVARCV_CONST_HANDLER ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_shift_left_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_shift_left_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SR_SPEC_TMPVARCV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13167,7 +13212,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SR_SPEC_TMPVARCV_CONST_HANDLER ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_shift_right_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_shift_right_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TMPVARCV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13210,7 +13255,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TMPVARCV_CONST goto is_smaller_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TMPVARCV_CONST_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13253,7 +13298,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TM goto is_smaller_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TMPVARCV_CONST_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13296,7 +13341,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TM goto is_smaller_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVARCV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13343,7 +13388,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVA goto is_smaller_or_equal_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVARCV_CONST_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13390,7 +13435,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUA goto is_smaller_or_equal_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVARCV_CONST_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13437,7 +13482,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUA goto is_smaller_or_equal_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_OR_SPEC_TMPVARCV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13455,7 +13500,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_OR_SPEC_TMPVARC ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_bw_or_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_bw_or_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_AND_SPEC_TMPVARCV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13473,7 +13518,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_AND_SPEC_TMPVAR ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_bw_and_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_bw_and_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_XOR_SPEC_TMPVARCV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13491,7 +13536,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_XOR_SPEC_TMPVAR ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_bw_xor_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_bw_xor_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_TMPVARCV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14041,7 +14086,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_TMPVARCV_ } } - ZEND_VM_TAIL_CALL(zend_add_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_add_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_TMPVARCV_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14079,7 +14124,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_TMPVARCV_ } } - ZEND_VM_TAIL_CALL(zend_sub_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_sub_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_TMPVARCV_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14120,7 +14165,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_TMPVARCV_TMPVARCV_HAN } } - ZEND_VM_TAIL_CALL(zend_mul_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_mul_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_TMPVARCV_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14147,7 +14192,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_TMPVARCV_TMPVARCV_HAN } } - ZEND_VM_TAIL_CALL(zend_mod_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_mod_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SL_SPEC_TMPVARCV_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14168,7 +14213,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SL_SPEC_TMPVARCV_TMPVARCV_HAND ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_shift_left_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_shift_left_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SR_SPEC_TMPVARCV_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14187,7 +14232,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SR_SPEC_TMPVARCV_TMPVARCV_HAND ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_shift_right_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_shift_right_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TMPVARCV_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14230,7 +14275,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TMPVARCV_TMPVA goto is_smaller_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TMPVARCV_TMPVARCV_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14273,7 +14318,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TM goto is_smaller_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TMPVARCV_TMPVARCV_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14316,7 +14361,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_SPEC_TM goto is_smaller_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVARCV_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14363,7 +14408,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVA goto is_smaller_or_equal_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVARCV_TMPVARCV_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14410,7 +14455,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUA goto is_smaller_or_equal_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVARCV_TMPVARCV_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14457,7 +14502,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUA goto is_smaller_or_equal_double; } } - ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_OR_SPEC_TMPVARCV_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14475,7 +14520,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_OR_SPEC_TMPVARC ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_bw_or_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_bw_or_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_AND_SPEC_TMPVARCV_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14493,7 +14538,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_AND_SPEC_TMPVAR ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_bw_and_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_bw_and_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_XOR_SPEC_TMPVARCV_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14511,7 +14556,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BW_XOR_SPEC_TMPVAR ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_TAIL_CALL(zend_bw_xor_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_bw_xor_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -15806,7 +15851,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_CONST_HAN } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_CONST_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -15864,7 +15909,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_CONST_JMP } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_CONST_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -15922,7 +15967,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_CONST_JMP } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -15980,7 +16025,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_CONST } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_CONST_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -16038,7 +16083,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_CONST } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_CONST_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -16096,7 +16141,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_CONST } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SPACESHIP_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -16820,7 +16865,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_TMPVAR_CONST_HANDLER } } } - ZEND_VM_TAIL_CALL(zend_case_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_case_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -17299,7 +17344,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_TMPVAR_HA } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_TMPVAR_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -17357,7 +17402,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_TMPVAR_JM } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_TMPVAR_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -17415,7 +17460,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_TMPVAR_TMPVAR_JM } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -17473,7 +17518,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_TMPVA } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_TMPVAR_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -17531,7 +17576,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_TMPVA } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_TMPVAR_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -17589,7 +17634,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_TMPVAR_TMPVA } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SPACESHIP_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -18285,7 +18330,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_TMPVAR_TMPVAR_HANDLE } } } - ZEND_VM_TAIL_CALL(zend_case_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_case_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -18495,7 +18540,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_TMPVAR_VAR_HAN ZEND_VM_SMART_BRANCH(result, 1); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(ZEND_OPCODE_HANDLER_ARGS_EX int type) { USE_OPLINE zval *varname; @@ -18598,17 +18643,17 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_R_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_R)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_W_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_W)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_RW_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_RW)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -18616,17 +18661,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMPVAR_UNU int fetch_type = (UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) ? BP_VAR_W : BP_VAR_R; - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(fetch_type ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX fetch_type)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_UNSET)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_IS_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_IS)); } /* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */ @@ -19692,7 +19737,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_TMPVAR_CV_HANDLER(ZE } } } - ZEND_VM_TAIL_CALL(zend_case_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_case_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -20068,7 +20113,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC USE_OPLINE zval *expr; zval *result = EX_VAR(opline->result.var); - HashTable *ht; SAVE_OPLINE(); expr = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); @@ -20101,53 +20145,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC } if (opline->extended_value == IS_ARRAY) { - if (IS_TMP_VAR == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { - if (Z_TYPE_P(expr) != IS_NULL) { - ZVAL_ARR(result, zend_new_array(1)); - expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); - if (IS_TMP_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } else { - ZVAL_EMPTY_ARRAY(result); - } - } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { - /* Optimized version without rebuilding properties HashTable */ - ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); - } else { - HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); - if (obj_ht) { - /* fast copy */ - ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, - (Z_OBJCE_P(expr)->default_properties_count || - Z_OBJ_P(expr)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht)))); - zend_release_properties(obj_ht); - } else { - ZVAL_EMPTY_ARRAY(result); - } - } + zend_cast_zval_to_array(result, expr, IS_TMP_VAR); } else { ZEND_ASSERT(opline->extended_value == IS_OBJECT); - ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); - if (Z_TYPE_P(expr) == IS_ARRAY) { - ht = zend_symtable_to_proptable(Z_ARR_P(expr)); - if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { - /* TODO: try not to duplicate immutable arrays as well ??? */ - ht = zend_array_dup(ht); - } - Z_OBJ_P(result)->properties = ht; - } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); - expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); - if (IS_TMP_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } + zend_cast_zval_to_object(result, expr, IS_TMP_VAR); } } @@ -20710,7 +20711,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_TMP_CONST_HAN } } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { send_val_by_ref: - ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(arg_num, arg ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX arg_num, arg)); } value = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); ZVAL_COPY_VALUE(arg, value); @@ -21519,7 +21520,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN } zend_reference *ref = NULL; - void *cache_slot = CACHE_ADDR(opline->op2.num); if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { ref = Z_REF_P(retval_ref); @@ -21536,7 +21536,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } @@ -21570,7 +21570,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_TMP_UNUSED_HA } } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { send_val_by_ref: - ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(arg_num, arg ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX arg_num, arg)); } value = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); ZVAL_COPY_VALUE(arg, value); @@ -21607,7 +21607,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_T } } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { send_val_by_ref: - ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(arg_num, arg ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_cannot_pass_by_ref_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX arg_num, arg)); } value = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); ZVAL_COPY_VALUE(arg, value); @@ -22735,7 +22735,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC USE_OPLINE zval *expr; zval *result = EX_VAR(opline->result.var); - HashTable *ht; SAVE_OPLINE(); expr = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -22769,53 +22768,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC } if (opline->extended_value == IS_ARRAY) { - if (IS_VAR == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { - if (Z_TYPE_P(expr) != IS_NULL) { - ZVAL_ARR(result, zend_new_array(1)); - expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); - if (IS_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } else { - ZVAL_EMPTY_ARRAY(result); - } - } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { - /* Optimized version without rebuilding properties HashTable */ - ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); - } else { - HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); - if (obj_ht) { - /* fast copy */ - ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, - (Z_OBJCE_P(expr)->default_properties_count || - Z_OBJ_P(expr)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht)))); - zend_release_properties(obj_ht); - } else { - ZVAL_EMPTY_ARRAY(result); - } - } + zend_cast_zval_to_array(result, expr, IS_VAR); } else { ZEND_ASSERT(opline->extended_value == IS_OBJECT); - ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); - if (Z_TYPE_P(expr) == IS_ARRAY) { - ht = zend_symtable_to_proptable(Z_ARR_P(expr)); - if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { - /* TODO: try not to duplicate immutable arrays as well ??? */ - ht = zend_array_dup(ht); - } - Z_OBJ_P(result)->properties = ht; - } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); - expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); - if (IS_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } + zend_cast_zval_to_object(result, expr, IS_VAR); } } @@ -24048,12 +24004,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -24125,14 +24083,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -24202,12 +24158,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -24279,14 +24237,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -24356,12 +24312,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -24433,14 +24391,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -24510,12 +24466,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -24587,14 +24545,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -25885,8 +25841,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_ } bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; - if (UNEXPECTED(is_constant_deprecated)) { + if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { + CONST_PROTECT_RECURSION(c); zend_deprecated_class_constant(c, constant_name); + CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -26454,8 +26412,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_ } bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; - if (UNEXPECTED(is_constant_deprecated)) { + if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { + CONST_PROTECT_RECURSION(c); zend_deprecated_class_constant(c, constant_name); + CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -27039,12 +26999,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -27116,14 +27078,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -27193,12 +27153,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -27270,14 +27232,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -27347,12 +27307,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -27424,14 +27386,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -27501,12 +27461,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -27578,14 +27540,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -29995,7 +29955,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN } zend_reference *ref = NULL; - void *cache_slot = CACHE_ADDR(opline->op2.num); if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { ref = Z_REF_P(retval_ref); @@ -30012,7 +29971,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } @@ -31392,12 +31351,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -31469,14 +31430,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -31546,12 +31505,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -31623,14 +31584,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -31700,12 +31659,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -31777,14 +31738,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -31854,12 +31813,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -31931,14 +31892,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -34139,12 +34098,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -34216,14 +34177,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -34293,12 +34252,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -34370,14 +34331,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -34447,12 +34406,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -34524,14 +34485,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -34601,12 +34560,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -34678,14 +34639,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -35293,8 +35252,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS } bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; - if (UNEXPECTED(is_constant_deprecated)) { + if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { + CONST_PROTECT_RECURSION(c); zend_deprecated_class_constant(c, constant_name); + CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -35652,8 +35613,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS } bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; - if (UNEXPECTED(is_constant_deprecated)) { + if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { + CONST_PROTECT_RECURSION(c); zend_deprecated_class_constant(c, constant_name); + CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -36307,12 +36270,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -36384,14 +36349,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -36461,12 +36424,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -36538,14 +36503,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -36615,12 +36578,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -36692,14 +36657,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -36769,12 +36732,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -36846,14 +36811,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -37785,7 +37748,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED } zend_reference *ref = NULL; - void *cache_slot = CACHE_ADDR(opline->op2.num); if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { ref = Z_REF_P(retval_ref); @@ -37802,7 +37764,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } @@ -38953,12 +38915,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -39030,14 +38994,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -39107,12 +39069,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -39184,14 +39148,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -39261,12 +39223,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -39338,14 +39302,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -39415,12 +39377,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -39492,14 +39456,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -40970,7 +40932,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO USE_OPLINE zval *expr; zval *result = EX_VAR(opline->result.var); - HashTable *ht; SAVE_OPLINE(); expr = _get_zval_ptr_cv_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); @@ -41003,53 +40964,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO } if (opline->extended_value == IS_ARRAY) { - if (IS_CV == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) { - if (Z_TYPE_P(expr) != IS_NULL) { - ZVAL_ARR(result, zend_new_array(1)); - expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr); - if (IS_CV == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } else { - ZVAL_EMPTY_ARRAY(result); - } - } else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(expr)) { - /* Optimized version without rebuilding properties HashTable */ - ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); - } else { - HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); - if (obj_ht) { - /* fast copy */ - ZVAL_ARR(result, zend_proptable_to_symtable(obj_ht, - (Z_OBJCE_P(expr)->default_properties_count || - Z_OBJ_P(expr)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht)))); - zend_release_properties(obj_ht); - } else { - ZVAL_EMPTY_ARRAY(result); - } - } + zend_cast_zval_to_array(result, expr, IS_CV); } else { ZEND_ASSERT(opline->extended_value == IS_OBJECT); - ZVAL_OBJ(result, zend_objects_new(zend_standard_class_def)); - if (Z_TYPE_P(expr) == IS_ARRAY) { - ht = zend_symtable_to_proptable(Z_ARR_P(expr)); - if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) { - /* TODO: try not to duplicate immutable arrays as well ??? */ - ht = zend_array_dup(ht); - } - Z_OBJ_P(result)->properties = ht; - } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); - expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); - if (IS_CV == IS_CONST) { - if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); - } else { - if (Z_OPT_REFCOUNTED_P(expr)) Z_ADDREF_P(expr); - } - } + zend_cast_zval_to_object(result, expr, IS_CV); } } @@ -42176,7 +42094,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CONST_HANDLER } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CONST_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -42234,7 +42152,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CONST_JMPZ_HA } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CONST_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -42292,7 +42210,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CONST_JMPNZ_H } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -42350,7 +42268,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CONST_HAN } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CONST_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -42408,7 +42326,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CONST_JMP } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CONST_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -42466,7 +42384,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CONST_JMP } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SPACESHIP_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -43353,12 +43271,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -43430,14 +43350,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -43507,12 +43425,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -43584,14 +43504,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -43661,12 +43579,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -43738,14 +43658,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -43815,12 +43733,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -43892,14 +43812,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -46129,7 +46047,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_TMPVAR_HANDLE } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_TMPVAR_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -46187,7 +46105,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_TMPVAR_JMPZ_H } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_TMPVAR_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -46245,7 +46163,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_TMPVAR_JMPNZ_ } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -46303,7 +46221,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_TMPVAR_HA } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_TMPVAR_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -46361,7 +46279,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_TMPVAR_JM } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_TMPVAR_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -46419,7 +46337,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_TMPVAR_JM } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SPACESHIP_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -47305,12 +47223,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -47382,14 +47302,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -47459,12 +47377,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -47536,14 +47456,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -47613,12 +47531,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -47690,14 +47610,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -47767,12 +47685,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -47844,14 +47764,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -49750,7 +49668,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_UNUSED_H ZEND_VM_NEXT_OPCODE_EX(1, 2); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_UNUSED(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_UNUSED(ZEND_OPCODE_HANDLER_ARGS_EX int type) { USE_OPLINE zval *varname; @@ -49853,17 +49771,17 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_R_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_R)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_W_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_W)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_RW_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_RW)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -49871,17 +49789,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_UNUSED_ int fetch_type = (UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) ? BP_VAR_W : BP_VAR_R; - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(fetch_type ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX fetch_type)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_UNSET)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_IS_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX BP_VAR_IS)); } /* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */ @@ -50586,7 +50504,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU } zend_reference *ref = NULL; - void *cache_slot = CACHE_ADDR(opline->op2.num); if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { ref = Z_REF_P(retval_ref); @@ -50603,7 +50520,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } @@ -51632,7 +51549,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CV_HANDLER(ZE } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CV_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -51690,7 +51607,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CV_JMPZ_HANDL } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CV_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -51748,7 +51665,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_EQUAL_SPEC_CV_CV_JMPNZ_HAND } } } - ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -51806,7 +51723,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CV_HANDLE } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CV_JMPZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -51864,7 +51781,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CV_JMPZ_H } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CV_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -51922,7 +51839,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_EQUAL_SPEC_CV_CV_JMPNZ_ } } } - ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_is_not_equal_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX op1, op2)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SPACESHIP_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -52804,12 +52721,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -52881,14 +52800,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -52958,12 +52875,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -53035,14 +52954,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -53112,12 +53029,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -53189,14 +53108,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -53266,12 +53183,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ void **cache_slot = CACHE_ADDR(opline->extended_value); uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); zval *property_val; + zend_property_info *prop_info; if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); + +assign_obj_simple: property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { - zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (prop_info != NULL) { value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; @@ -53343,14 +53262,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } else { ZEND_ASSERT(IS_HOOKED_PROPERTY_OFFSET(prop_offset)); if (ZEND_IS_PROPERTY_HOOK_SIMPLE_WRITE(prop_offset)) { - zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2); - property_val = OBJ_PROP(zobj, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; - } else { - goto fast_assign_obj; + prop_info = CACHED_PTR_EX(cache_slot + 2); + prop_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; } + goto assign_obj_simple; } /* Fall through to write_property for hooks. */ } @@ -55036,10 +54953,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDL # pragma GCC optimize("no-gcse") # pragma GCC optimize("no-ivopts") #endif +#ifdef _WIN64 +/* See save_xmm_x86_64_ms_masm.asm */ +void execute_ex_real(zend_execute_data *ex) +#else ZEND_API void execute_ex(zend_execute_data *ex) +#endif { DCL_OPLINE +#if defined(__GNUC__) && defined(__aarch64__) + __asm__ __volatile__ (""::: "v8","v9","v10","v11","v12","v13","v14","v15"); +#endif + #if defined(ZEND_VM_IP_GLOBAL_REG) || defined(ZEND_VM_FP_GLOBAL_REG) struct { #ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE @@ -58582,19 +58508,17 @@ ZEND_API void execute_ex(zend_execute_data *ex) #endif /* ZEND_CHECK_STACK_LIMIT */ while (1) { -#if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG) - int ret; -#endif #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) HYBRID_SWITCH() { -#else +#else /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */ #if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG) ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); if (UNEXPECTED(!OPLINE)) { #else - if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0)) { -#endif + opline = ((opcode_handler_t)opline->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (UNEXPECTED(((uintptr_t)opline & ZEND_VM_ENTER_BIT))) { #endif +#endif /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */ #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) HYBRID_CASE(ZEND_ASSIGN_STATIC_PROP_OP_SPEC): VM_TRACE(ZEND_ASSIGN_STATIC_PROP_OP_SPEC) @@ -64189,7 +64113,7 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); VM_TRACE_OP_END(ZEND_NULL) HYBRID_BREAK(); /* Never reached */ -#else +#else /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */ #ifdef ZEND_VM_FP_GLOBAL_REG execute_data = vm_stack_data.orig_execute_data; # ifdef ZEND_VM_IP_GLOBAL_REG @@ -64197,7 +64121,8 @@ ZEND_API void execute_ex(zend_execute_data *ex) # endif return; #else - if (EXPECTED(ret > 0)) { + opline = (const zend_op*)((uintptr_t)opline & ~ZEND_VM_ENTER_BIT); + if (EXPECTED(opline != NULL)) { execute_data = EG(current_execute_data); ZEND_VM_LOOP_INTERRUPT_CHECK(); } else { @@ -64207,7 +64132,7 @@ ZEND_API void execute_ex(zend_execute_data *ex) return; } #endif -#endif +#endif /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */ } } @@ -68441,6 +68366,7 @@ ZEND_API int ZEND_FASTCALL zend_vm_call_opcode_handler(zend_execute_data* ex) #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) opcode_handler_t handler; #endif + DCL_OPLINE; int ret; #ifdef ZEND_VM_IP_GLOBAL_REG const zend_op *orig_opline = opline; @@ -68468,8 +68394,23 @@ ZEND_API int ZEND_FASTCALL zend_vm_call_opcode_handler(zend_execute_data* ex) ret = -1; } #else - ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - SAVE_OPLINE(); + opline = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +if (UNEXPECTED(((uintptr_t)opline & ZEND_VM_ENTER_BIT))) { + opline = (const zend_op*)((uintptr_t)opline & ~ZEND_VM_ENTER_BIT); + if (EXPECTED(opline)) { + /* ZEND_VM_ENTER() or ZEND_VM_LEAVE() */ + ret = EG(current_execute_data) != ex ? (int)(EG(current_execute_data)->prev_execute_data != ex) + 1 : 0; + execute_data = EG(current_execute_data); + SAVE_OPLINE(); + } else { + /* ZEND_VM_RETURN() */ + ret = -1; + } + } else { + /* ZEND_VM_CONTINUE() */ + SAVE_OPLINE(); + ret = 0; + } #endif #ifdef ZEND_VM_FP_GLOBAL_REG execute_data = orig_execute_data; diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 717d4ffd3e8af..6fecd39346a70 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -1,3 +1,5 @@ +#include "Zend/zend_vm_opcodes.h" + {%DEFINES%} #if (ZEND_VM_KIND != ZEND_VM_KIND_CALL) && (ZEND_GCC_VERSION >= 4000) && !defined(__clang__) @@ -5,10 +7,19 @@ # pragma GCC optimize("no-gcse") # pragma GCC optimize("no-ivopts") #endif +#ifdef _WIN64 +/* See save_xmm_x86_64_ms_masm.asm */ +void {%EXECUTOR_NAME%}_ex_real(zend_execute_data *ex) +#else ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *ex) +#endif { DCL_OPLINE +#if defined(__GNUC__) && defined(__aarch64__) + __asm__ __volatile__ (""::: "v8","v9","v10","v11","v12","v13","v14","v15"); +#endif + {%HELPER_VARS%} {%INTERNAL_LABELS%} diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 7f503e78e2935..5a4a31b60b8d3 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -818,7 +818,7 @@ function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec) { if (isset($matches[2])) { // extra args $args = substr(preg_replace("/,\s*[A-Za-z0-9_]*\s*,\s*([^,)\s]*)\s*/", ", $1", $matches[2]), 2); - return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(" . $args. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC))"; + return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX " . $args . "))"; } return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))"; } @@ -852,7 +852,7 @@ function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec, $name) { if (isset($matches[2])) { // extra args $args = substr(preg_replace("/,\s*[A-Za-z0-9_]*\s*,\s*([^,)\s]*)\s*/", ", $1", $matches[2]), 2); - return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(" . $args. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC))"; + return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX " . $args . "))"; } return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))"; } @@ -1164,7 +1164,7 @@ function gen_helper($f, $spec, $kind, $name, $op1, $op2, $param, $code, $lineno, out($f, "static$zend_attributes ZEND_OPCODE_HANDLER_RET$zend_fastcall $spec_name(ZEND_OPCODE_HANDLER_ARGS)\n"); } else { // Helper with parameter - out($f, "static$zend_attributes ZEND_OPCODE_HANDLER_RET$zend_fastcall $spec_name($param ZEND_OPCODE_HANDLER_ARGS_DC)\n"); + out($f, "static$zend_attributes ZEND_OPCODE_HANDLER_RET$zend_fastcall $spec_name(ZEND_OPCODE_HANDLER_ARGS_EX $param)\n"); } break; case ZEND_VM_KIND_SWITCH: @@ -1870,13 +1870,13 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); out($f,"# define ZEND_OPCODE_HANDLER_ARGS void\n"); out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS_EX\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX\n"); out($f,"#else\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC , ZEND_OPCODE_HANDLER_ARGS\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC , ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data, const zend_op *opline\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data, opline\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS_EX ZEND_OPCODE_HANDLER_ARGS, \n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX ZEND_OPCODE_HANDLER_ARGS_PASSTHRU, \n"); out($f,"#endif\n"); out($f,"\n"); out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); @@ -1902,10 +1902,10 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"# define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE\n"); } out($f,"#else\n"); - out($f,"# define ZEND_OPCODE_HANDLER_RET int\n"); + out($f,"# define ZEND_OPCODE_HANDLER_RET const zend_op *\n"); out($f,"# define ZEND_VM_TAIL_CALL(call) return call\n"); - out($f,"# define ZEND_VM_CONTINUE() return 0\n"); - out($f,"# define ZEND_VM_RETURN() return -1\n"); + out($f,"# define ZEND_VM_CONTINUE() return opline\n"); + out($f,"# define ZEND_VM_RETURN() return (const zend_op*)ZEND_VM_ENTER_BIT\n"); if ($kind == ZEND_VM_KIND_HYBRID) { out($f,"# define ZEND_VM_HOT\n"); } @@ -1914,8 +1914,8 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"\n"); out($f,"typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);\n"); out($f,"\n"); - out($f,"#define DCL_OPLINE\n"); out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); + out($f,"# define DCL_OPLINE\n"); out($f,"# define OPLINE opline\n"); out($f,"# define USE_OPLINE\n"); out($f,"# define LOAD_OPLINE() opline = EX(opline)\n"); @@ -1924,12 +1924,13 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"# define SAVE_OPLINE() EX(opline) = opline\n"); out($f,"# define SAVE_OPLINE_EX() SAVE_OPLINE()\n"); out($f,"#else\n"); - out($f,"# define OPLINE EX(opline)\n"); - out($f,"# define USE_OPLINE const zend_op *opline = EX(opline);\n"); - out($f,"# define LOAD_OPLINE()\n"); - out($f,"# define LOAD_OPLINE_EX()\n"); - out($f,"# define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE()\n"); - out($f,"# define SAVE_OPLINE()\n"); + out($f,"# define DCL_OPLINE const zend_op *opline;\n"); + out($f,"# define OPLINE opline\n"); + out($f,"# define USE_OPLINE\n"); + out($f,"# define LOAD_OPLINE() opline = EX(opline)\n"); + out($f,"# define LOAD_OPLINE_EX() opline = EX(opline)\n"); + out($f,"# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); + out($f,"# define SAVE_OPLINE() EX(opline) = opline\n"); out($f,"# define SAVE_OPLINE_EX()\n"); out($f,"#endif\n"); out($f,"#define HANDLE_EXCEPTION() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); @@ -1943,9 +1944,10 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"# define ZEND_VM_ENTER() opline = EG(current_execute_data)->opline; ZEND_VM_ENTER_EX()\n"); out($f,"# define ZEND_VM_LEAVE() return 2\n"); out($f,"#else\n"); - out($f,"# define ZEND_VM_ENTER_EX() return 1\n"); - out($f,"# define ZEND_VM_ENTER() return 1\n"); - out($f,"# define ZEND_VM_LEAVE() return 2\n"); + out($f,"# define ZEND_VM_ENTER_BIT 1ULL\n"); + out($f,"# define ZEND_VM_ENTER_EX() return (zend_op*)((uintptr_t)opline | ZEND_VM_ENTER_BIT)\n"); + out($f,"# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); + out($f,"# define ZEND_VM_LEAVE() return (zend_op*)((uintptr_t)opline | ZEND_VM_ENTER_BIT)\n"); out($f,"#endif\n"); out($f,"#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); out($f,"#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); @@ -2119,12 +2121,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) } break; case "ZEND_VM_CONTINUE_LABEL": - if ($kind == ZEND_VM_KIND_CALL || $kind == ZEND_VM_KIND_HYBRID) { - // Only SWITCH dispatch method use it - out($f,"#if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG)\n"); - out($f,$m[1]."\tint ret;".$m[3]."\n"); - out($f,"#endif\n"); - } else if ($kind == ZEND_VM_KIND_SWITCH) { + if ($kind == ZEND_VM_KIND_SWITCH) { // Only SWITCH dispatch method use it out($f,"zend_vm_continue:".$m[3]."\n"); } else { @@ -2143,16 +2140,17 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) case ZEND_VM_KIND_HYBRID: out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); out($f, $m[1]."HYBRID_SWITCH()".$m[3]."\n"); - out($f,"#else\n"); + out($f,"#else /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */\n"); case ZEND_VM_KIND_CALL: out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); out($f, $m[1]."((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); out($f, $m[1]."if (UNEXPECTED(!OPLINE))".$m[3]."\n"); out($f,"#else\n"); - out($f, $m[1]."if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0))".$m[3]."\n"); + out($f, $m[1]."opline = ((opcode_handler_t)opline->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + out($f, $m[1]."if (UNEXPECTED(((uintptr_t)opline & ZEND_VM_ENTER_BIT)))".$m[3]."\n"); out($f,"#endif\n"); if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#endif\n"); + out($f,"#endif /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */\n"); } break; } @@ -2168,7 +2166,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) if ($kind == ZEND_VM_KIND_CALL || $kind == ZEND_VM_KIND_HYBRID) { // Executor is defined as a set of functions if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#else\n"); + out($f,"#else /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */\n"); } out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n" . @@ -2178,18 +2176,19 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) "# endif\n" . $m[1]."return;\n" . "#else\n" . - $m[1]."if (EXPECTED(ret > 0)) {\n" . + $m[1]."opline = (const zend_op*)((uintptr_t)opline & ~ZEND_VM_ENTER_BIT);\n". + $m[1]."if (EXPECTED(opline != NULL)) {\n" . $m[1]."\texecute_data = EG(current_execute_data);\n". $m[1]."\tZEND_VM_LOOP_INTERRUPT_CHECK();\n". $m[1]."} else {\n" . "# ifdef ZEND_VM_IP_GLOBAL_REG\n" . $m[1]."\topline = vm_stack_data.orig_opline;\n" . - "# endif\n". + "# endif\n" . $m[1]."\treturn;\n". $m[1]."}\n". "#endif\n"); if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#endif\n"); + out($f,"#endif /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */\n"); } } break; @@ -2335,6 +2334,8 @@ function gen_vm_opcodes_header( ): string { $str = HEADER_TEXT; $str .= "#ifndef ZEND_VM_OPCODES_H\n#define ZEND_VM_OPCODES_H\n\n"; + $str .= "#include \"Zend/zend_portability.h\"\n"; + $str .= "\n"; $str .= "#define ZEND_VM_SPEC\t\t" . ZEND_VM_SPEC . "\n"; $str .= "#define ZEND_VM_LINES\t\t" . ZEND_VM_LINES . "\n"; $str .= "#define ZEND_VM_KIND_CALL\t" . ZEND_VM_KIND_CALL . "\n"; @@ -2416,6 +2417,12 @@ function gen_vm($def, $skel) { $max_opcode = 0; $extra_num = 256; foreach ($in as $line) { + // Handle Windows line endings, GH-17836; since a bunch of regular + // expressions below test for a newline at the end, just update the + // ending + if (substr($line, -2) === "\r\n") { + $line = substr_replace($line, "\n", -2); + } ++$lineno; if (strpos($line,"ZEND_VM_HANDLER(") === 0 || strpos($line,"ZEND_VM_INLINE_HANDLER(") === 0 || @@ -2962,6 +2969,7 @@ function gen_vm($def, $skel) { out($f, "\topcode_handler_t handler;\n"); out($f,"#endif\n"); } + out($f, "\tDCL_OPLINE;\n"); out($f, "\tint ret;\n"); out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n"); out($f, "\tconst zend_op *orig_opline = opline;\n"); @@ -2995,8 +3003,24 @@ function gen_vm($def, $skel) { out($f, "\t\tret = -1;\n"); out($f, "\t}\n"); out($f, "#else\n"); - out($f, "\tret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); - out($f, "\tSAVE_OPLINE();\n"); + out($f, "\topline = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + + out($f, "if (UNEXPECTED(((uintptr_t)opline & ZEND_VM_ENTER_BIT))) {\n"); + out($f, "\t\topline = (const zend_op*)((uintptr_t)opline & ~ZEND_VM_ENTER_BIT);\n"); + out($f, "\t\tif (EXPECTED(opline)) {\n"); + out($f, "\t\t\t/* ZEND_VM_ENTER() or ZEND_VM_LEAVE() */\n"); + out($f, "\t\t\tret = EG(current_execute_data) != ex ? (int)(EG(current_execute_data)->prev_execute_data != ex) + 1 : 0;\n"); + out($f, "\t\t\texecute_data = EG(current_execute_data);\n"); + out($f, "\t\t\tSAVE_OPLINE();\n"); + out($f, "\t\t} else {\n"); + out($f, "\t\t\t/* ZEND_VM_RETURN() */\n"); + out($f, "\t\t\tret = -1;\n"); + out($f, "\t\t}\n"); + out($f, "\t} else {\n"); + out($f, "\t\t/* ZEND_VM_CONTINUE() */\n"); + out($f, "\t\tSAVE_OPLINE();\n"); + out($f, "\t\tret = 0;\n"); + out($f, "\t}\n"); out($f, "#endif\n"); out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n"); out($f, "\texecute_data = orig_execute_data;\n"); diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 202dfd3f734f3..d7d4d9e770b5b 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -299,8 +299,8 @@ static uint32_t zend_vm_opcodes_flags[210] = { 0x00000000, 0x01040310, 0x00000003, - 0x00040110, - 0x00040310, + 0x00000110, + 0x00000310, 0x00001307, 0x00001301, 0x00001301, @@ -360,7 +360,7 @@ static uint32_t zend_vm_opcodes_flags[210] = { 0x00000007, 0x00040003, 0x09000007, - 0x0000a103, + 0x00000103, 0x00002003, 0x03000001, 0x00000005, @@ -400,7 +400,7 @@ static uint32_t zend_vm_opcodes_flags[210] = { 0x00000003, 0x00000020, 0x00003000, - 0x00040110, + 0x00000110, 0x00000000, 0x00000007, 0x00000105, diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index d472b5b9660f5..e15b1a19d5cdb 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -21,6 +21,8 @@ #ifndef ZEND_VM_OPCODES_H #define ZEND_VM_OPCODES_H +#include "Zend/zend_portability.h" + #define ZEND_VM_SPEC 1 #define ZEND_VM_LINES 0 #define ZEND_VM_KIND_CALL 1 diff --git a/benchmark/generate_diff.php b/benchmark/generate_diff.php index b62f55c06d9e4..94c020df4b998 100644 --- a/benchmark/generate_diff.php +++ b/benchmark/generate_diff.php @@ -10,6 +10,7 @@ function main(?string $headCommitHash, ?string $baseCommitHash) { $repo = __DIR__ . '/repos/data'; cloneRepo($repo, 'git@github.com:php/benchmarking-data.git'); + $baseCommitHash = find_benchmarked_commit_hash($repo, $baseCommitHash); $headSummaryFile = $repo . '/' . substr($headCommitHash, 0, 2) . '/' . $headCommitHash . '/summary.json'; $baseSummaryFile = $repo . '/' . substr($baseCommitHash, 0, 2) . '/' . $baseCommitHash . '/summary.json'; if (!file_exists($headSummaryFile)) { @@ -60,6 +61,28 @@ function formatDiff(?int $baseInstructions, int $headInstructions): string { return sprintf('%.2f%%', $instructionDiff / $baseInstructions * 100); } +function find_benchmarked_commit_hash(string $repo, string $commitHash): ?string { + $repeat = 10; + + while (true) { + if ($repeat-- <= 0) { + fwrite(STDERR, "Count not find benchmarked commit hash\n"); + exit(1); + } + $summaryFile = $repo . '/' . substr($commitHash, 0, 2) . '/' . $commitHash . '/summary.json'; + if (file_exists($summaryFile)) { + break; + } + $commitHash = trim(runCommand( + ['git', 'rev-parse', $commitHash . '^'], + dirname(__DIR__), + printCommand: false, + )->stdout); + } + + return $commitHash; +} + $headCommitHash = $argv[1] ?? null; $baseCommitHash = $argv[2] ?? null; $output = main($headCommitHash, $baseCommitHash); diff --git a/benchmark/shared.php b/benchmark/shared.php index 450101770b28b..0f58a2a1bf870 100644 --- a/benchmark/shared.php +++ b/benchmark/shared.php @@ -5,12 +5,14 @@ class ProcessResult { public $stderr; } -function runCommand(array $args, ?string $cwd = null): ProcessResult { +function runCommand(array $args, ?string $cwd = null, bool $printCommand = true): ProcessResult { $cmd = implode(' ', array_map('escapeshellarg', $args)); $pipes = null; $result = new ProcessResult(); $descriptorSpec = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; - fwrite(STDOUT, "> $cmd\n"); + if ($printCommand) { + fwrite(STDOUT, "> $cmd\n"); + } $processHandle = proc_open($cmd, $descriptorSpec, $pipes, $cwd ?? getcwd(), null); $stdin = $pipes[0]; diff --git a/build/Makefile.global b/build/Makefile.global index 321b0ed4ff3fc..32605a203e188 100644 --- a/build/Makefile.global +++ b/build/Makefile.global @@ -18,6 +18,10 @@ libphp.la: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(LIBTOOL) --tag=CC --mode=link $(CC) $(LIBPHP_CFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) -rpath $(phptempdir) $(EXTRA_LDFLAGS) $(LDFLAGS) $(PHP_RPATHS) $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(EXTRA_LIBS) $(ZEND_EXTRA_LIBS) -o $@ -@$(LIBTOOL) --tag=CC --mode=install cp $@ $(phptempdir)/$@ >/dev/null 2>&1 +libphp.dylib: libphp.la + $(LIBTOOL) --tag=CC --mode=link $(CC) -dynamiclib $(LIBPHP_CFLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) -rpath $(phptempdir) -install_name @rpath/$@ $(EXTRA_LDFLAGS) $(LDFLAGS) $(PHP_RPATHS) $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(EXTRA_LIBS) $(ZEND_EXTRA_LIBS) -o $@ + -@$(LIBTOOL) --silent --tag=CC --mode=install cp $@ $(phptempdir)/$@ >/dev/null 2>&1 + libs/libphp.bundle: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(CC) $(MH_BUNDLE_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS) $(PHP_GLOBAL_OBJS:.lo=.o) $(PHP_SAPI_OBJS:.lo=.o) $(PHP_FRAMEWORKS) $(EXTRA_LIBS) $(ZEND_EXTRA_LIBS) -o $@ && cp $@ libs/libphp.so @@ -85,7 +89,7 @@ PHP_TEST_SHARED_EXTENSIONS = ` \ . $$i; $(top_srcdir)/build/shtool echo -n -- " -d zend_extension=$(top_builddir)/modules/$$dlname"; \ done; \ fi` -PHP_DEPRECATED_DIRECTIVES_REGEX = '^(magic_quotes_(gpc|runtime|sybase)?|(zend_)?extension(_debug)?(_ts)?)[\t\ ]*=' +PHP_DEPRECATED_DIRECTIVES_REGEX = '^(magic_quotes_(gpc|runtime|sybase)?|(zend_)?extension(_debug)?(_ts)?|session\.sid_(length|bits_per_character))[\t\ ]*=' test: all @if test ! -z "$(PHP_EXECUTABLE)" && test -x "$(PHP_EXECUTABLE)"; then \ diff --git a/build/gen_stub.php b/build/gen_stub.php index f060cc1cebae0..d3ffc04c3f890 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -36,6 +36,13 @@ PHP_85_VERSION_ID, ]; +// file_put_contents() but with a success message printed after saving +function reportFilePutContents(string $filename, string $content): void { + if (file_put_contents($filename, $content)) { + echo "Saved $filename\n"; + } +} + /** * @return FileInfo[] */ @@ -121,8 +128,8 @@ function processStubFile(string $stubFile, Context $context, bool $includeOnly = $context->allConstInfos, $stubHash ); - if (($context->forceRegeneration || $stubHash !== $oldStubHash) && file_put_contents($arginfoFile, $arginfoCode)) { - echo "Saved $arginfoFile\n"; + if ($context->forceRegeneration || $stubHash !== $oldStubHash) { + reportFilePutContents($arginfoFile, $arginfoCode); } if ($fileInfo->shouldGenerateLegacyArginfo()) { @@ -146,8 +153,8 @@ function processStubFile(string $stubFile, Context $context, bool $includeOnly = $context->allConstInfos, $stubHash ); - if (($context->forceRegeneration || $stubHash !== $oldStubHash) && file_put_contents($legacyFile, $arginfoCode)) { - echo "Saved $legacyFile\n"; + if ($context->forceRegeneration || $stubHash !== $oldStubHash) { + reportFilePutContents($legacyFile, $arginfoCode); } } @@ -185,8 +192,8 @@ class Context { } class ArrayType extends SimpleType { - public /* readonly */ Type $keyType; - public /* readonly */ Type $valueType; + private /* readonly */ Type $keyType; + private /* readonly */ Type $valueType; public static function createGenericArray(): self { @@ -524,6 +531,8 @@ public function equals(SimpleType $other): bool { } } +// Instances of Type are immutable and do not need to be cloned +// when held by an object that is cloned class Type { /** @var SimpleType[] */ public /* readonly */ array $types; @@ -877,7 +886,7 @@ public function isUnknown(): bool } class ConstName extends AbstractConstName { - public /* readonly */ string $const; + private /* readonly */ string $const; public function __construct(?Name $namespace, string $const) { @@ -914,7 +923,7 @@ public function getDeclarationName(): string class ClassConstName extends AbstractConstName { public /* readonly */ Name $class; - public /* readonly */ string $const; + private /* readonly */ string $const; public function __construct(Name $class, string $const) { @@ -940,7 +949,7 @@ public function getDeclarationName(): string class PropertyName implements VariableLikeName { public /* readonly */ Name $class; - public /* readonly */ string $property; + private /* readonly */ string $property; public function __construct(Name $class, string $property) { @@ -1148,12 +1157,12 @@ private function setRefcount(?string $refcount): void class FuncInfo { public /* readonly */ FunctionOrMethodName $name; - public /* readonly */ int $classFlags; + private /* readonly */ int $classFlags; public int $flags; public /* readonly */ ?string $aliasType; public ?FunctionOrMethodName $alias; - public /* readonly */ bool $isDeprecated; - public bool $supportsCompileTimeEval; + private /* readonly */ bool $isDeprecated; + private bool $supportsCompileTimeEval; public /* readonly */ bool $verify; /** @var ArgInfo[] */ public /* readonly */ array $args; @@ -1161,12 +1170,12 @@ class FuncInfo { public /* readonly */ int $numRequiredArgs; public /* readonly */ ?string $cond; public bool $isUndocumentable; - public ?int $minimumPhpVersionIdCompatibility; + private ?int $minimumPhpVersionIdCompatibility; /** @var AttributeInfo[] */ public array $attributes; /** @var FramelessFunctionInfo[] */ - public array $framelessFunctionInfos; - public ?ExposedDocComment $exposedDocComment; + private array $framelessFunctionInfos; + private ?ExposedDocComment $exposedDocComment; /** * @param ArgInfo[] $args @@ -1308,7 +1317,7 @@ public function getDeclaration(): ?string return $name->getDeclaration(); } - public function getFramelessDeclaration(FuncInfo $funcInfo): ?string { + public function getFramelessDeclaration(): ?string { if (empty($this->framelessFunctionInfos)) { return null; } @@ -1510,9 +1519,13 @@ private function getArginfoFlagsByPhpVersions(): array } foreach ($this->attributes as $attr) { - if ($attr->class === "Deprecated") { - $flags[] = "ZEND_ACC_DEPRECATED"; - break; + switch ($attr->class) { + case "Deprecated": + $flags[] = "ZEND_ACC_DEPRECATED"; + break; + case "NoDiscard": + $flags[] = "ZEND_ACC_NODISCARD"; + break; } } @@ -2079,6 +2092,16 @@ public function getMethodSynopsisElement(array $funcMap, array $aliasMap, DOMDoc return $methodSynopsis; } + /** @param FuncInfo[] $generatedFuncInfos */ + public function findEquivalent(array $generatedFuncInfos): ?FuncInfo { + foreach ($generatedFuncInfos as $generatedFuncInfo) { + if ($generatedFuncInfo->equalsApartFromNameAndRefcount($this)) { + return $generatedFuncInfo; + } + } + return null; + } + public function __clone() { foreach ($this->args as $key => $argInfo) { @@ -2151,7 +2174,7 @@ public function enterNode(Node $expr) static function (Expr $expr) use ($allConstInfos, &$isUnknownConstValue) { // $expr is a ConstFetch with a name of a C macro here if (!$expr instanceof Expr\ConstFetch) { - throw new Exception($this->getVariableTypeName() . " " . $this->name->__toString() . " has an unsupported value"); + throw new Exception("Expression at line " . $expr->getStartLine() . " must be a global, non-magic constant"); } $constName = $expr->name->__toString(); @@ -2274,11 +2297,11 @@ abstract class VariableLike public int $flags; public ?Type $type; public /* readonly */ ?Type $phpDocType; - public /* readonly */ ?string $link; - public ?int $phpVersionIdMinimumCompatibility; + private /* readonly */ ?string $link; + protected ?int $phpVersionIdMinimumCompatibility; /** @var AttributeInfo[] */ public array $attributes; - public /* readonly */ ?ExposedDocComment $exposedDocComment; + protected /* readonly */ ?ExposedDocComment $exposedDocComment; /** * @var AttributeInfo[] $attributes @@ -2456,12 +2479,12 @@ class ConstInfo extends VariableLike { public /* readonly */ AbstractConstName $name; public /* readonly */ Expr $value; - public bool $isDeprecated; - public /* readonly */ ?string $valueString; + private bool $isDeprecated; + private /* readonly */ ?string $valueString; public /* readonly */ ?string $cond; public /* readonly */ ?string $cValue; public /* readonly */ bool $isUndocumentable; - public /* readonly */ bool $isFileCacheAllowed; + private /* readonly */ bool $isFileCacheAllowed; /** * @var AttributeInfo[] $attributes @@ -2814,12 +2837,12 @@ protected function addModifiersToFieldSynopsis(DOMDocument $doc, DOMElement $fie class PropertyInfo extends VariableLike { - public /* readonly */ int $classFlags; + private /* readonly */ int $classFlags; public /* readonly */ PropertyName $name; - public /* readonly */ ?Expr $defaultValue; - public /* readonly */ ?string $defaultValueString; - public /* readonly */ bool $isDocReadonly; - public /* readonly */ bool $isVirtual; + private /* readonly */ ?Expr $defaultValue; + private /* readonly */ ?string $defaultValueString; + private /* readonly */ bool $isDocReadonly; + private /* readonly */ bool $isVirtual; // Map possible variable names to the known string constant, see // ZEND_KNOWN_STRINGS @@ -3139,18 +3162,11 @@ protected function addModifiersToFieldSynopsis(DOMDocument $doc, DOMElement $fie $fieldsynopsisElement->appendChild($doc->createElement("modifier", "readonly")); } } - - public function __clone() - { - if ($this->type) { - $this->type = clone $this->type; - } - } } class EnumCaseInfo { - public /* readonly */ string $name; - public /* readonly */ ?Expr $value; + private /* readonly */ string $name; + private /* readonly */ ?Expr $value; public function __construct(string $name, ?Expr $value) { $this->name = $name; @@ -3179,7 +3195,7 @@ public function getDeclaration(array $allConstInfos): string { class AttributeInfo { public /* readonly */ string $class; /** @var \PhpParser\Node\Arg[] */ - public /* readonly */ array $args; + private /* readonly */ array $args; /** @param \PhpParser\Node\Arg[] $args */ public function __construct(string $class, array $args) { @@ -3227,6 +3243,22 @@ public function generateCode(string $invocation, string $nameSuffix, array $allC } return $code; } + + /** + * @param array> $attributeGroups + * @return AttributeInfo[] + */ + public static function createFromGroups(array $attributeGroups): array { + $attributes = []; + + foreach ($attributeGroups as $attrGroup) { + foreach ($attrGroup->attrs as $attr) { + $attributes[] = new AttributeInfo($attr->name->toString(), $attr->args); + } + } + + return $attributes; + } } class ClassInfo { @@ -3234,13 +3266,13 @@ class ClassInfo { public int $flags; public string $type; public /* readonly */ ?string $alias; - public /* readonly */ ?SimpleType $enumBackingType; - public /* readonly */ bool $isDeprecated; - public bool $isStrictProperties; + private /* readonly */ ?SimpleType $enumBackingType; + private /* readonly */ bool $isDeprecated; + private bool $isStrictProperties; /** @var AttributeInfo[] */ public array $attributes; - public ?ExposedDocComment $exposedDocComment; - public bool $isNotSerializable; + private ?ExposedDocComment $exposedDocComment; + private bool $isNotSerializable; /** @var Name[] */ public /* readonly */ array $extends; /** @var Name[] */ @@ -3248,11 +3280,11 @@ class ClassInfo { /** @var ConstInfo[] */ public /* readonly */ array $constInfos; /** @var PropertyInfo[] */ - public /* readonly */ array $propertyInfos; + private /* readonly */ array $propertyInfos; /** @var FuncInfo[] */ public array $funcInfos; /** @var EnumCaseInfo[] */ - public /* readonly */ array $enumCaseInfos; + private /* readonly */ array $enumCaseInfos; public /* readonly */ ?string $cond; public ?int $phpVersionIdMinimumCompatibility; public /* readonly */ bool $isUndocumentable; @@ -4050,6 +4082,36 @@ class FileInfo { public bool $legacyArginfoGeneration = false; private ?int $minimumPhpVersionIdCompatibility = null; + /** @param array $fileTags */ + public function __construct(array $fileTags) { + foreach ($fileTags as $tag) { + if ($tag->name === 'generate-function-entries') { + $this->generateFunctionEntries = true; + $this->declarationPrefix = $tag->value ? $tag->value . " " : ""; + } else if ($tag->name === 'generate-legacy-arginfo') { + if ($tag->value && !in_array((int) $tag->value, ALL_PHP_VERSION_IDS, true)) { + throw new Exception( + "Legacy PHP version must be one of: \"" . PHP_70_VERSION_ID . "\" (PHP 7.0), \"" . PHP_80_VERSION_ID . "\" (PHP 8.0), " . + "\"" . PHP_81_VERSION_ID . "\" (PHP 8.1), \"" . PHP_82_VERSION_ID . "\" (PHP 8.2), \"" . PHP_83_VERSION_ID . "\" (PHP 8.3), " . + "\"" . PHP_84_VERSION_ID . "\" (PHP 8.4), \"" . PHP_85_VERSION_ID . "\" (PHP 8.5), \"" . $tag->value . "\" provided" + ); + } + + $this->minimumPhpVersionIdCompatibility = ($tag->value ? (int) $tag->value : PHP_70_VERSION_ID); + } else if ($tag->name === 'generate-class-entries') { + $this->generateClassEntries = true; + $this->declarationPrefix = $tag->value ? $tag->value . " " : ""; + } else if ($tag->name === 'undocumentable') { + $this->isUndocumentable = true; + } + } + + // Generating class entries require generating function/method entries + if ($this->generateClassEntries && !$this->generateFunctionEntries) { + $this->generateFunctionEntries = true; + } + } + /** * @return iterable */ @@ -4101,10 +4163,6 @@ public function __clone() } } - public function setMinimumPhpVersionIdCompatibility(?int $minimumPhpVersionIdCompatibility) { - $this->minimumPhpVersionIdCompatibility = $minimumPhpVersionIdCompatibility; - } - public function getMinimumPhpVersionIdCompatibility(): ?int { // Non-legacy arginfo files are always PHP 8.0+ compatible if (!$this->legacyArginfoGeneration && @@ -4196,28 +4254,44 @@ public function escape(): string { public function getLength(): int { return strlen($this->docComment); } -} -/** @return DocCommentTag[] */ -function parseDocComments(array $comments): array { - $tags = []; - foreach ($comments as $comment) { - if ($comment instanceof DocComment) { - $tags = array_merge($tags, parseDocComment($comment)); + /** @param array $comments */ + public static function extractExposedComment(array $comments): ?ExposedDocComment { + $exposedDocComment = null; + + foreach ($comments as $comment) { + $text = $comment->getText(); + $matches = []; + $pattern = "#^(\s*\/\*\*)(\s*@genstubs-expose-comment-block)(\s*)$#m"; + + if (preg_match($pattern, $text, $matches) !== 1) { + continue; + } + + if ($exposedDocComment !== null) { + throw new Exception("Only one PHPDoc comment block can be exposed"); + } + + $exposedDocComment = preg_replace($pattern, '$1$3', $text); } - } - return $tags; + return $exposedDocComment ? new ExposedDocComment($exposedDocComment) : null; + } } /** @return DocCommentTag[] */ -function parseDocComment(DocComment $comment): array { - $commentText = substr($comment->getText(), 2, -2); +function parseDocComments(array $comments): array { $tags = []; - foreach (explode("\n", $commentText) as $commentLine) { - $regex = '/^\*\s*@([a-z-]+)(?:\s+(.+))?$/'; - if (preg_match($regex, trim($commentLine), $matches)) { - $tags[] = new DocCommentTag($matches[1], $matches[2] ?? null); + foreach ($comments as $comment) { + if (!($comment instanceof DocComment)) { + continue; + } + $commentText = substr($comment->getText(), 2, -2); + foreach (explode("\n", $commentText) as $commentLine) { + $regex = '/^\*\s*@([a-z-]+)(?:\s+(.+))?$/'; + if (preg_match($regex, trim($commentLine), $matches)) { + $tags[] = new DocCommentTag($matches[1], $matches[2] ?? null); + } } } @@ -4382,7 +4456,7 @@ function parseFunctionLike( $type, isset($docParamTypes[$varName]) ? Type::fromString($docParamTypes[$varName]) : null, $param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null, - createAttributes($param->attrGroups) + AttributeInfo::createFromGroups($param->attrGroups) ); if (!$param->default && !$param->variadic) { $numRequiredArgs = $i + 1; @@ -4421,9 +4495,9 @@ function parseFunctionLike( $cond, $isUndocumentable, $minimumPhpVersionIdCompatibility, - createAttributes($func->attrGroups), + AttributeInfo::createFromGroups($func->attrGroups), $framelessFunctionInfos, - createExposedDocComment($comments) + ExposedDocComment::extractExposedComment($comments) ); } catch (Exception $e) { throw new Exception($name . "(): " .$e->getMessage()); @@ -4500,7 +4574,7 @@ function parseConstLike( $link, $phpVersionIdMinimumCompatibility, $attributes, - createExposedDocComment($comments), + ExposedDocComment::extractExposedComment($comments), $isFileCacheAllowed ); } @@ -4567,7 +4641,7 @@ function parseProperty( $link, $phpVersionIdMinimumCompatibility, $attributes, - createExposedDocComment($comments) + ExposedDocComment::extractExposedComment($comments) ); } @@ -4612,7 +4686,7 @@ function parseClass( } } - $attributes = createAttributes($class->attrGroups); + $attributes = AttributeInfo::createFromGroups($class->attrGroups); foreach ($attributes as $attribute) { switch ($attribute->class) { case 'AllowDynamicProperties': @@ -4662,7 +4736,7 @@ function parseClass( $isDeprecated, $isStrictProperties, $attributes, - createExposedDocComment($comments), + ExposedDocComment::extractExposedComment($comments), $isNotSerializable, $extends, $implements, @@ -4676,45 +4750,6 @@ function parseClass( ); } -/** - * @param array> $attributeGroups - * @return Attribute[] - */ -function createAttributes(array $attributeGroups): array { - $attributes = []; - - foreach ($attributeGroups as $attrGroup) { - foreach ($attrGroup->attrs as $attr) { - $attributes[] = new AttributeInfo($attr->name->toString(), $attr->args); - } - } - - return $attributes; -} - -/** @param array $comments */ -function createExposedDocComment(array $comments): ?ExposedDocComment { - $exposedDocComment = null; - - foreach ($comments as $comment) { - $text = $comment->getText(); - $matches = []; - $pattern = "#^(\s*\/\*\*)(\s*@genstubs-expose-comment-block)(\s*)$#m"; - - if (preg_match($pattern, $text, $matches) !== 1) { - continue; - } - - if ($exposedDocComment !== null) { - throw new Exception("Only one PHPDoc comment block can be exposed"); - } - - $exposedDocComment = preg_replace($pattern, '$1$3', $text); - } - - return $exposedDocComment ? new ExposedDocComment($exposedDocComment) : null; -} - function handlePreprocessorConditions(array &$conds, Stmt $stmt): ?string { foreach ($stmt->getComments() as $comment) { $text = trim($comment->getText()); @@ -4749,16 +4784,10 @@ function getFileDocComments(array $stmts): array { return []; } - $comments = $stmts[0]->getComments(); - - $result = []; - foreach ($comments as $comment) { - if ($comment instanceof DocComment) { - $result[] = $comment; - } - } - - return $result; + return array_filter( + $stmts[0]->getComments(), + static fn ( $comment ): bool => $comment instanceof DocComment + ); } function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstract $prettyPrinter) { @@ -4834,7 +4863,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac $cond, $fileInfo->isUndocumentable, $fileInfo->getMinimumPhpVersionIdCompatibility(), - createAttributes($classStmt->attrGroups) + AttributeInfo::createFromGroups($classStmt->attrGroups) ); } } else if ($classStmt instanceof Stmt\Property) { @@ -4851,7 +4880,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac $classStmt->getComments(), $prettyPrinter, $fileInfo->getMinimumPhpVersionIdCompatibility(), - createAttributes($classStmt->attrGroups) + AttributeInfo::createFromGroups($classStmt->attrGroups) ); } } else if ($classStmt instanceof Stmt\ClassMethod) { @@ -4918,37 +4947,8 @@ protected function pName_FullyQualified(Name\FullyQualified $node): string { $stmts = $parser->parse($code); $nodeTraverser->traverse($stmts); - $fileInfo = new FileInfo; - $fileDocComments = getFileDocComments($stmts); - if ($fileDocComments !== []) { - $fileTags = parseDocComments($fileDocComments); - foreach ($fileTags as $tag) { - if ($tag->name === 'generate-function-entries') { - $fileInfo->generateFunctionEntries = true; - $fileInfo->declarationPrefix = $tag->value ? $tag->value . " " : ""; - } else if ($tag->name === 'generate-legacy-arginfo') { - if ($tag->value && !in_array((int) $tag->value, ALL_PHP_VERSION_IDS, true)) { - throw new Exception( - "Legacy PHP version must be one of: \"" . PHP_70_VERSION_ID . "\" (PHP 7.0), \"" . PHP_80_VERSION_ID . "\" (PHP 8.0), " . - "\"" . PHP_81_VERSION_ID . "\" (PHP 8.1), \"" . PHP_82_VERSION_ID . "\" (PHP 8.2), \"" . PHP_83_VERSION_ID . "\" (PHP 8.3), " . - "\"" . PHP_84_VERSION_ID . "\" (PHP 8.4), \"" . PHP_85_VERSION_ID . "\" (PHP 8.5), \"" . $tag->value . "\" provided" - ); - } - - $fileInfo->setMinimumPhpVersionIdCompatibility($tag->value ? (int) $tag->value : PHP_70_VERSION_ID); - } else if ($tag->name === 'generate-class-entries') { - $fileInfo->generateClassEntries = true; - $fileInfo->declarationPrefix = $tag->value ? $tag->value . " " : ""; - } else if ($tag->name === 'undocumentable') { - $fileInfo->isUndocumentable = true; - } - } - } - - // Generating class entries require generating function/method entries - if ($fileInfo->generateClassEntries && !$fileInfo->generateFunctionEntries) { - $fileInfo->generateFunctionEntries = true; - } + $fileTags = parseDocComments(getFileDocComments($stmts)); + $fileInfo = new FileInfo($fileTags); handleStatements($fileInfo, $stmts, $prettyPrinter); return $fileInfo; @@ -5067,16 +5067,6 @@ function funcInfoToCode(FileInfo $fileInfo, FuncInfo $funcInfo): string { return $code . "\n"; } -/** @param FuncInfo[] $generatedFuncInfos */ -function findEquivalentFuncInfo(array $generatedFuncInfos, FuncInfo $funcInfo): ?FuncInfo { - foreach ($generatedFuncInfos as $generatedFuncInfo) { - if ($generatedFuncInfo->equalsApartFromNameAndRefcount($funcInfo)) { - return $generatedFuncInfo; - } - } - return null; -} - /** * @template T * @param iterable $infos @@ -5150,7 +5140,7 @@ function generateArgInfoCode( $fileInfo->getAllFuncInfos(), "\n", static function (FuncInfo $funcInfo) use (&$generatedFuncInfos, $fileInfo) { /* If there already is an equivalent arginfo structure, only emit a #define */ - if ($generatedFuncInfo = findEquivalentFuncInfo($generatedFuncInfos, $funcInfo)) { + if ($generatedFuncInfo = $funcInfo->findEquivalent($generatedFuncInfos)) { $code = sprintf( "#define %s %s\n", $funcInfo->getArgInfoName(), $generatedFuncInfo->getArgInfoName() @@ -5172,7 +5162,7 @@ static function (FuncInfo $funcInfo) use (&$generatedFuncInfos, $fileInfo) { $framelessFunctionCode = generateCodeWithConditions( $fileInfo->getAllFuncInfos(), "\n", static function (FuncInfo $funcInfo) { - return $funcInfo->getFramelessDeclaration($funcInfo); + return $funcInfo->getFramelessDeclaration(); } ); @@ -6293,9 +6283,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc if ($replacePredefinedConstants) { foreach ($predefinedConstants as $filename => $content) { - if (file_put_contents($filename, $content)) { - echo "Saved $filename\n"; - } + reportFilePutContents($filename, $content); } } } @@ -6310,9 +6298,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc } foreach ($classSynopses as $filename => $content) { - if (file_put_contents("$classSynopsesDirectory/$filename", $content)) { - echo "Saved $filename\n"; - } + reportFilePutContents("$classSynopsesDirectory/$filename", $content); } } } @@ -6322,9 +6308,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc if ($replaceClassSynopses) { foreach ($classSynopses as $filename => $content) { - if (file_put_contents($filename, $content)) { - echo "Saved $filename\n"; - } + reportFilePutContents($filename, $content); } } } @@ -6343,9 +6327,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc mkdir(dirname($path)); } - if (file_put_contents($path, $content)) { - echo "Saved $filename\n"; - } + reportFilePutContents($path, $content); } } } @@ -6355,9 +6337,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc if ($replaceMethodSynopses) { foreach ($methodSynopses as $filename => $content) { - if (file_put_contents($filename, $content)) { - echo "Saved $filename\n"; - } + reportFilePutContents($filename, $content); } } } @@ -6366,9 +6346,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc $filename = dirname(__FILE__, 2) . "/Zend/Optimizer/zend_func_infos.h"; $optimizerInfo = generateOptimizerInfo($funcMap); - if (file_put_contents($filename, $optimizerInfo)) { - echo "Saved $filename\n"; - } + reportFilePutContents($filename, $optimizerInfo); } if ($verifyManual) { diff --git a/build/php.m4 b/build/php.m4 index 53684cf011d9a..640f01008009d 100644 --- a/build/php.m4 +++ b/build/php.m4 @@ -779,6 +779,14 @@ AC_DEFUN([PHP_BUILD_SHARED],[ php_lo=$shared_lo ]) +dnl +dnl PHP_BUILD_SHARED_DYLIB +dnl +AC_DEFUN([PHP_BUILD_SHARED_DYLIB],[ + PHP_BUILD_SHARED + OVERALL_TARGET=libphp.dylib +]) + dnl dnl PHP_BUILD_STATIC dnl @@ -894,6 +902,7 @@ AC_DEFUN([PHP_SELECT_SAPI],[ case "$2" in static[)] PHP_BUILD_STATIC;; shared[)] PHP_BUILD_SHARED;; + shared-dylib[)] PHP_BUILD_SHARED_DYLIB;; bundle[)] PHP_BUILD_BUNDLE;; esac install_sapi="install-sapi" diff --git a/docs/release-process.md b/docs/release-process.md index 46557524988c5..36963b4318ead 100644 --- a/docs/release-process.md +++ b/docs/release-process.md @@ -257,7 +257,7 @@ slightly different steps. We'll call attention where the steps differ. For example, if the RC is `8.2.1RC1` then the version numbers in the version branch should be bumped to `8.2.2-dev`. We do this regardless of whether we build a new RC to make sure `version_compare()` works correctly. See - [Bump for 8.1.8-dev][] for a real example. + [PHP 8.3 is now for PHP 8.3.21-dev][] commit for a real example. Commit the changes to the version branch. @@ -291,6 +291,11 @@ slightly different steps. We'll call attention where the steps differ. > > Local-only release branches should not be pushed! + Do not forget to merge up PHP-X.Y all the way to master. When resolving + the conflicts, ignore the changes from PHP-X.Y in higher branches. It + means using something like `git checkout --ours .` when on PHP.X.Y+1 or + master after the merge resulting in the conflicts. + 11. Run the following using the release tag to export the tree, create the `configure` script, and build and compress three tarballs (`.tar.gz`, `.tar.bz2` and `.tar.xz`). @@ -1098,7 +1103,7 @@ volunteers to begin the selection process for the next release managers. [Prepare for PHP 8.1.0RC1]: https://github.com/php/php-src/commit/5764414eb8900ae98020a3c20693f4fb793efa99 [Update NEWS for PHP 8.2.0 alpha2]: https://github.com/php/php-src/commit/418f7211f71658d79d934861be20f277db96fe2c [Update NEWS for PHP 8.2.0RC6]: https://github.com/php/php-src/commit/4ccc414961a70200d638ca281a35f893226d74e2 -[Bump for 8.1.8-dev]: https://github.com/php/php-src/commit/3b6ee1eb19c14c3339ebfcf5c967065a9f828971 +[PHP 8.3 is now for PHP 8.3.21-dev]: https://github.com/php/php-src/commit/b57f425cfe20a11003253427424cc0517483550b [GitHub command line tool]: https://cli.github.com [Announce 8.1.0RC3]: https://github.com/php/web-qa/commit/f264b711fd3827803b79bbb342959eae57ea502b [8.1.6RC1]: https://github.com/php/web-qa/commit/e6d61ad7a9d8be0b1cd159af29f3b9cbdde33384 diff --git a/docs/source/miscellaneous/stubs.rst b/docs/source/miscellaneous/stubs.rst index 385eddc5be72f..3899fe3084196 100644 --- a/docs/source/miscellaneous/stubs.rst +++ b/docs/source/miscellaneous/stubs.rst @@ -13,11 +13,11 @@ code, but instead contain empty function and method bodies. A very basic stub lo /** @var float */ const WEIGHT = 6.8; - class Atmopshere { + class Atmosphere { public function calculateBar(): float {} } - function fahrenheitToCelcius(float $fahrenheitToCelcius): float {} + function fahrenheitToCelsius(float $fahrenheitToCelsius): float {} Any kind of symbol can be declared via stubs. Every type can be used, with the exception of disjunctive normal form (DNF) types. Additional meta information can be added via PHPDoc blocks or @@ -33,17 +33,17 @@ using namespace blocks: /** @var float */ const WEIGHT_TON = 6.8; - class Atmopshere { + class Atmosphere { public function calculateBar(): float {} } } namespace Algorithms { - function fahrenheitToCelcius(float $fahrenheit): float {} + function fahrenheitToCelsius(float $fahrenheit): float {} } The above example declares the global constants ``ANIMAL`` and ``WEIGHT_TON``, and the class -``Atmopshere`` in the top-level namespace. The ``fahrenheitToCelcius()`` function is declared to be +``Atmosphere`` in the top-level namespace. The ``fahrenheitToCelsius()`` function is declared to be in the ``Algorithms`` namespace. ******************** @@ -77,11 +77,11 @@ The arginfo file matching our first example looks like: /* This is a generated file, edit the .stub.php file instead. * Stub hash: e4ed788d54a20272a92a3f6618b73d48ec848f97 */ - ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_fahrenheitToCelcius, 0, 1, IS_DOUBLE, 0) - ZEND_ARG_TYPE_INFO(0, fahrenheitToCelcius, IS_DOUBLE, 0) + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_fahrenheitToCelsius, 0, 1, IS_DOUBLE, 0) + ZEND_ARG_TYPE_INFO(0, fahrenheitToCelsius, IS_DOUBLE, 0) ZEND_END_ARG_INFO() - ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Atmopshere_calculateBar, 0, 0, IS_DOUBLE, 0) + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Atmosphere_calculateBar, 0, 0, IS_DOUBLE, 0) ZEND_END_ARG_INFO() The hash that is included in the file makes sure that stub files are not reprocessed unless the stub @@ -186,24 +186,24 @@ In order to generate these, add the file-level ``@generate-function-entries`` PH public function calculateBar(): float {} } - function fahrenheitToCelcius(float $fahrenheit): float {} + function fahrenheitToCelsius(float $fahrenheit): float {} Now, the following C code is generated: .. code:: c - ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_fahrenheitToCelcius, 0, 1, IS_DOUBLE, 0) + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_fahrenheitToCelsius, 0, 1, IS_DOUBLE, 0) ZEND_ARG_TYPE_INFO(0, fahrenheit, IS_DOUBLE, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Atmosphere_calculateBar, 0, 0, IS_DOUBLE, 0) ZEND_END_ARG_INFO() - ZEND_FUNCTION(fahrenheitToCelcius); + ZEND_FUNCTION(fahrenheitToCelsius); ZEND_METHOD(Atmosphere, calculateBar); static const zend_function_entry ext_functions[] = { - ZEND_FE(fahrenheitToCelcius, arginfo_fahrenheitToCelcius) + ZEND_FE(fahrenheitToCelsius, arginfo_fahrenheitToCelsius) ZEND_FE_END }; @@ -762,7 +762,7 @@ Running it with the stub examples that are used in this guide, the following war Warning: Missing class synopsis for Number Warning: Missing class synopsis for Elephant Warning: Missing class synopsis for Atmosphere - Warning: Missing method synopsis for fahrenheitToCelcius() + Warning: Missing method synopsis for fahrenheitToCelsius() Warning: Missing method synopsis for Atmosphere::calculateBar() ********************** diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index 233045bd7cd7e..1e0e6d14d81eb 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -807,8 +807,8 @@ PHP_FUNCTION(bcround) goto cleanup; } - bc_round(num, precision, mode, &result); - RETVAL_NEW_STR(bc_num2str_ex(result, result->n_scale)); + size_t scale = bc_round(num, precision, mode, &result); + RETVAL_NEW_STR(bc_num2str_ex(result, scale)); cleanup: { bc_free_num(&num); @@ -1164,7 +1164,7 @@ static zend_always_inline bcmath_number_obj_t *bcmath_number_new_obj(bc_num ret, return intern; } -static zend_result bcmath_number_parse_num(zval *zv, zend_object **obj, zend_string **str, zend_long *lval) +static zend_result bcmath_number_parse_num(const zval *zv, zend_object **obj, zend_string **str, zend_long *lval) { if (Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), bcmath_number_ce)) { *obj = Z_OBJ_P(zv); @@ -1372,7 +1372,7 @@ static int bcmath_number_compare(zval *op1, zval *op2) } static zend_always_inline zend_result bc_num_from_obj_or_str_or_long_with_err( - bc_num *num, size_t *scale, zend_object *obj, zend_string *str, zend_long lval, uint32_t arg_num) + bc_num *num, size_t *scale, const zend_object *obj, const zend_string *str, zend_long lval, uint32_t arg_num) { size_t full_scale = 0; if (UNEXPECTED(bc_num_from_obj_or_str_or_long(num, &full_scale, obj, str, lval) == FAILURE)) { @@ -1799,9 +1799,10 @@ PHP_METHOD(BcMath_Number, round) bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); bc_num ret = NULL; - bc_round(intern->num, precision, rounding_mode, &ret); + size_t scale = bc_round(intern->num, precision, rounding_mode, &ret); + bc_rm_trailing_zeros(ret); - bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, ret->n_scale); + bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, scale); RETURN_OBJ(&new_intern->std); } diff --git a/ext/bcmath/libbcmath/src/bcmath.h b/ext/bcmath/libbcmath/src/bcmath.h index f7e14019bd336..1f05ad51f7f26 100644 --- a/ext/bcmath/libbcmath/src/bcmath.h +++ b/ext/bcmath/libbcmath/src/bcmath.h @@ -157,7 +157,7 @@ bool bc_divmod(bc_num num1, bc_num num2, bc_num *quo, bc_num *rem, size_t scale) bc_num bc_floor_or_ceil(bc_num num, bool is_floor); -void bc_round(bc_num num, zend_long places, zend_long mode, bc_num *result); +size_t bc_round(bc_num num, zend_long places, zend_long mode, bc_num *result); typedef enum { OK, diff --git a/ext/bcmath/libbcmath/src/compare.c b/ext/bcmath/libbcmath/src/compare.c index 2c24dab777059..06ef246782089 100644 --- a/ext/bcmath/libbcmath/src/compare.c +++ b/ext/bcmath/libbcmath/src/compare.c @@ -41,8 +41,6 @@ bcmath_compare_result _bc_do_compare(bc_num n1, bc_num n2, size_t scale, bool use_sign) { - char *n1ptr, *n2ptr; - /* First, compare signs. */ if (use_sign && n1->n_sign != n2->n_sign) { /* @@ -91,8 +89,8 @@ bcmath_compare_result _bc_do_compare(bc_num n1, bc_num n2, size_t scale, bool us /* If we get here, they have the same number of integer digits. check the integer part and the equal length part of the fraction. */ size_t count = n1->n_len + MIN (n1_scale, n2_scale); - n1ptr = n1->n_value; - n2ptr = n2->n_value; + const char *n1ptr = n1->n_value; + const char *n2ptr = n2->n_value; while ((count > 0) && (*n1ptr == *n2ptr)) { n1ptr++; diff --git a/ext/bcmath/libbcmath/src/convert.c b/ext/bcmath/libbcmath/src/convert.c index bf3d9a9a415bf..5438b4c1c44e5 100644 --- a/ext/bcmath/libbcmath/src/convert.c +++ b/ext/bcmath/libbcmath/src/convert.c @@ -17,24 +17,22 @@ #include "bcmath.h" #include "convert.h" #include "private.h" -#ifdef __SSE2__ -# include -#endif +#include "simd.h" char *bc_copy_and_toggle_bcd(char *restrict dest, const char *source, const char *source_end) { const size_t bulk_shift = SWAR_REPEAT('0'); -#ifdef __SSE2__ - /* SIMD SSE2 bulk shift + copy */ - __m128i shift_vector = _mm_set1_epi8('0'); - while (source + sizeof(__m128i) <= source_end) { - __m128i bytes = _mm_loadu_si128((const __m128i *) source); - bytes = _mm_xor_si128(bytes, shift_vector); - _mm_storeu_si128((__m128i *) dest, bytes); +#ifdef HAVE_BC_SIMD_128 + /* SIMD SSE2 or NEON bulk shift + copy */ + bc_simd_128_t shift_vector = bc_simd_set_8x16('0'); + while (source + sizeof(bc_simd_128_t) <= source_end) { + bc_simd_128_t bytes = bc_simd_load_8x16((const bc_simd_128_t *) source); + bytes = bc_simd_xor_8x16(bytes, shift_vector); + bc_simd_store_8x16((bc_simd_128_t *) dest, bytes); - source += sizeof(__m128i); - dest += sizeof(__m128i); + source += sizeof(bc_simd_128_t); + dest += sizeof(bc_simd_128_t); } #endif diff --git a/ext/bcmath/libbcmath/src/convert.h b/ext/bcmath/libbcmath/src/convert.h index 6ddd447c8048e..73c38cd130107 100644 --- a/ext/bcmath/libbcmath/src/convert.h +++ b/ext/bcmath/libbcmath/src/convert.h @@ -34,11 +34,11 @@ static inline BC_VECTOR bc_partial_convert_to_vector(const char *n, size_t len) } BC_VECTOR num = 0; - BC_VECTOR base = 1; + BC_VECTOR digit_base_value = 1; for (size_t i = 0; i < len; i++) { - num += *n * base; - base *= BASE; + num += *n * digit_base_value; + digit_base_value *= BASE; n--; } @@ -57,4 +57,58 @@ static inline void bc_convert_to_vector(BC_VECTOR *n_vector, const char *nend, s } } +static inline void bc_convert_to_vector_with_zero_pad(BC_VECTOR *n_vector, const char *nend, size_t nlen, size_t zeros) +{ + while (zeros >= BC_VECTOR_SIZE) { + *n_vector = 0; + n_vector++; + zeros -= BC_VECTOR_SIZE; + } + + if (zeros > 0) { + *n_vector = 0; + BC_VECTOR digit_base_value = BC_POW_10_LUT[zeros]; + size_t len_to_write = MIN(BC_VECTOR_SIZE - zeros, nlen); + for (size_t i = 0; i < len_to_write; i++) { + *n_vector += *nend * digit_base_value; + digit_base_value *= BASE; + nend--; + } + n_vector++; + nlen -= len_to_write; + } + + if (nlen == 0) { + return; + } + + bc_convert_to_vector(n_vector, nend, nlen); +} + +static inline void bc_convert_vector_to_char(const BC_VECTOR *vector, char *nptr, char *nend, size_t arr_size) +{ + size_t i = 0; + while (i < arr_size - 1) { +#if BC_VECTOR_SIZE == 4 + bc_write_bcd_representation(vector[i], nend - 3); + nend -= 4; +#else + bc_write_bcd_representation(vector[i] / 10000, nend - 7); + bc_write_bcd_representation(vector[i] % 10000, nend - 3); + nend -= 8; +#endif + i++; + } + + /* + * The last digit may carry over. + * Also need to fill it to the end with zeros, so loop until the end of the string. + */ + BC_VECTOR last = vector[i]; + while (nend >= nptr) { + *nend-- = last % BASE; + last /= BASE; + } +} + #endif diff --git a/ext/bcmath/libbcmath/src/div.c b/ext/bcmath/libbcmath/src/div.c index ce9ae1e1dd792..24ec9a64d77fc 100644 --- a/ext/bcmath/libbcmath/src/div.c +++ b/ext/bcmath/libbcmath/src/div.c @@ -37,10 +37,6 @@ #include #include "zend_alloc.h" -static const BC_VECTOR POW_10_LUT[9] = { - 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 -}; - /* * This function should be used when the divisor is not split into multiple chunks, i.e. when the size of the array is one. * This is because the algorithm can be simplified. @@ -51,7 +47,7 @@ static inline void bc_fast_div( { size_t numerator_top_index = numerator_arr_size - 1; size_t quot_top_index = quot_arr_size - 1; - for (size_t i = 0; i < quot_arr_size - 1; i++) { + for (size_t i = 0; i < quot_top_index; i++) { if (numerator_vectors[numerator_top_index - i] < divisor_vector) { quot_vectors[quot_top_index - i] = 0; /* numerator_vectors[numerator_top_index - i] < divisor_vector, so there will be no overflow. */ @@ -74,7 +70,7 @@ static inline void bc_fast_div( */ static inline void bc_standard_div( BC_VECTOR *numerator_vectors, size_t numerator_arr_size, - BC_VECTOR *divisor_vectors, size_t divisor_arr_size, size_t divisor_len, + const BC_VECTOR *divisor_vectors, size_t divisor_arr_size, size_t divisor_len, BC_VECTOR *quot_vectors, size_t quot_arr_size ) { size_t numerator_top_index = numerator_arr_size - 1; @@ -174,8 +170,8 @@ static inline void bc_standard_div( divisor_top_digits = BC_VECTOR_SIZE; } - size_t high_part_shift = POW_10_LUT[BC_VECTOR_SIZE - divisor_top_digits + 1]; - size_t low_part_shift = POW_10_LUT[divisor_top_digits - 1]; + size_t high_part_shift = BC_POW_10_LUT[BC_VECTOR_SIZE - divisor_top_digits + 1]; + size_t low_part_shift = BC_POW_10_LUT[divisor_top_digits - 1]; BC_VECTOR divisor_high_part = divisor_vectors[divisor_top_index] * high_part_shift + divisor_vectors[divisor_top_index - 1] / low_part_shift; for (size_t i = 0; i < quot_arr_size; i++) { BC_VECTOR numerator_high_part = numerator_vectors[numerator_top_index - i] * high_part_shift + numerator_vectors[numerator_top_index - i - 1] / low_part_shift; @@ -255,77 +251,85 @@ static inline void bc_standard_div( } static void bc_do_div( - const char *numerator, size_t numerator_readable_len, size_t numerator_bottom_extension, - const char *divisor, size_t divisor_len, bc_num *quot, size_t quot_len + const char *numerator, size_t numerator_size, size_t numerator_readable_size, + const char *divisor, size_t divisor_size, + bc_num *quot, size_t quot_size ) { - size_t divisor_arr_size = (divisor_len + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE; - size_t numerator_arr_size = (numerator_readable_len + numerator_bottom_extension + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE; + size_t numerator_arr_size = BC_ARR_SIZE_FROM_LEN(numerator_size); + size_t divisor_arr_size = BC_ARR_SIZE_FROM_LEN(divisor_size); size_t quot_arr_size = numerator_arr_size - divisor_arr_size + 1; - size_t quot_real_arr_size = MIN(quot_arr_size, (quot_len + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE); + size_t quot_real_arr_size = MIN(quot_arr_size, BC_ARR_SIZE_FROM_LEN(quot_size)); - BC_VECTOR *numerator_vectors = safe_emalloc(numerator_arr_size + divisor_arr_size + quot_arr_size, sizeof(BC_VECTOR), 0); - BC_VECTOR *divisor_vectors = numerator_vectors + numerator_arr_size; - BC_VECTOR *quot_vectors = divisor_vectors + divisor_arr_size; + BC_VECTOR stack_vectors[BC_STACK_VECTOR_SIZE]; + size_t allocation_arr_size = numerator_arr_size + divisor_arr_size + quot_arr_size; - /* Fill with zeros and convert as many vector elements as needed */ - size_t numerator_vector_count = 0; - while (numerator_bottom_extension >= BC_VECTOR_SIZE) { - numerator_vectors[numerator_vector_count] = 0; - numerator_bottom_extension -= BC_VECTOR_SIZE; - numerator_vector_count++; + BC_VECTOR *numerator_vectors; + if (allocation_arr_size <= BC_STACK_VECTOR_SIZE) { + numerator_vectors = stack_vectors; + } else { + numerator_vectors = safe_emalloc(allocation_arr_size, sizeof(BC_VECTOR), 0); } + BC_VECTOR *divisor_vectors = numerator_vectors + numerator_arr_size; + BC_VECTOR *quot_vectors = divisor_vectors + divisor_arr_size; - size_t numerator_bottom_read_len = BC_VECTOR_SIZE - numerator_bottom_extension; - - size_t base; - size_t numerator_read = 0; - if (numerator_bottom_read_len < BC_VECTOR_SIZE) { - numerator_read = MIN(numerator_bottom_read_len, numerator_readable_len); - base = POW_10_LUT[numerator_bottom_extension]; - numerator_vectors[numerator_vector_count] = 0; - for (size_t i = 0; i < numerator_read; i++) { - numerator_vectors[numerator_vector_count] += *numerator * base; - base *= BASE; - numerator--; - } - numerator_vector_count++; - } + size_t numerator_extension = numerator_size > numerator_readable_size ? numerator_size - numerator_readable_size : 0; /* Bulk convert numerator and divisor to vectors */ - if (numerator_readable_len > numerator_read) { - bc_convert_to_vector(numerator_vectors + numerator_vector_count, numerator, numerator_readable_len - numerator_read); - } - bc_convert_to_vector(divisor_vectors, divisor, divisor_len); + size_t numerator_use_size = numerator_size - numerator_extension; + const char *numerator_end = numerator + numerator_use_size - 1; + bc_convert_to_vector_with_zero_pad(numerator_vectors, numerator_end, numerator_use_size, numerator_extension); + + const char *divisor_end = divisor + divisor_size - 1; + bc_convert_to_vector(divisor_vectors, divisor_end, divisor_size); /* Do the division */ if (divisor_arr_size == 1) { bc_fast_div(numerator_vectors, numerator_arr_size, divisor_vectors[0], quot_vectors, quot_arr_size); } else { - bc_standard_div(numerator_vectors, numerator_arr_size, divisor_vectors, divisor_arr_size, divisor_len, quot_vectors, quot_arr_size); + bc_standard_div(numerator_vectors, numerator_arr_size, divisor_vectors, divisor_arr_size, divisor_size, quot_vectors, quot_arr_size); } /* Convert to bc_num */ char *qptr = (*quot)->n_value; - char *qend = qptr + quot_len - 1; - - size_t i; - for (i = 0; i < quot_real_arr_size - 1; i++) { -#if BC_VECTOR_SIZE == 4 - bc_write_bcd_representation(quot_vectors[i], qend - 3); - qend -= 4; -#else - bc_write_bcd_representation(quot_vectors[i] / 10000, qend - 7); - bc_write_bcd_representation(quot_vectors[i] % 10000, qend - 3); - qend -= 8; -#endif + char *qend = qptr + (*quot)->n_len + (*quot)->n_scale - 1; + + bc_convert_vector_to_char(quot_vectors, qptr, qend, quot_real_arr_size); + + if (allocation_arr_size > BC_STACK_VECTOR_SIZE) { + efree(numerator_vectors); } +} + +static inline void bc_divide_by_one(bc_num numerator, bc_num *quot, size_t quot_scale) +{ + quot_scale = MIN(numerator->n_scale, quot_scale); + *quot = bc_new_num_nonzeroed(numerator->n_len, quot_scale); + char *qptr = (*quot)->n_value; + memcpy(qptr, numerator->n_value, numerator->n_len + quot_scale); +} - while (qend >= qptr) { - *qend-- = quot_vectors[i] % BASE; - quot_vectors[i] /= BASE; +static inline void bc_divide_by_pow_10( + const char *numeratorptr, size_t numerator_readable_size, bc_num *quot, size_t quot_size, size_t quot_scale) +{ + char *qptr = (*quot)->n_value; + for (size_t i = quot_size; i <= quot_scale; i++) { + *qptr++ = 0; } - efree(numerator_vectors); + size_t numerator_use_size = quot_size > numerator_readable_size ? numerator_readable_size : quot_size; + memcpy(qptr, numeratorptr, numerator_use_size); + qptr += numerator_use_size; + + if (numerator_use_size < (*quot)->n_len) { + /* e.g. 12.3 / 0.01 <=> 1230 */ + for (size_t i = numerator_use_size; i < (*quot)->n_len; i++) { + *qptr++ = 0; + } + (*quot)->n_scale = 0; + } else { + char *qend = (*quot)->n_value + (*quot)->n_len + (*quot)->n_scale; + (*quot)->n_scale -= qend - qptr; + } } bool bc_divide(bc_num numerator, bc_num divisor, bc_num *quot, size_t scale) @@ -336,166 +340,92 @@ bool bc_divide(bc_num numerator, bc_num divisor, bc_num *quot, size_t scale) } bc_free_num(quot); + size_t quot_scale = scale; /* If numerator is zero, the quotient is always zero. */ if (bc_is_zero(numerator)) { - *quot = bc_copy_num(BCG(_zero_)); - return true; + goto quot_zero; } /* If divisor is 1 / -1, the quotient's n_value is equal to numerator's n_value. */ if (_bc_do_compare(divisor, BCG(_one_), divisor->n_scale, false) == BCMATH_EQUAL) { - size_t quot_scale = MIN(numerator->n_scale, scale); - *quot = bc_new_num_nonzeroed(numerator->n_len, quot_scale); - char *qptr = (*quot)->n_value; - memcpy(qptr, numerator->n_value, numerator->n_len + quot_scale); + bc_divide_by_one(numerator, quot, quot_scale); (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS; - _bc_rm_leading_zeros(*quot); return true; } - char *numeratorptr = numerator->n_value; - char *numeratorend = numeratorptr + numerator->n_len + numerator->n_scale - 1; - size_t numerator_len = numerator->n_len; - size_t numerator_scale = numerator->n_scale; - - char *divisorptr = divisor->n_value; - char *divisorend = divisorptr + divisor->n_len + divisor->n_scale - 1; - size_t divisor_len = divisor->n_len; - size_t divisor_scale = divisor->n_scale; - size_t divisor_int_right_zeros = 0; - - /* remove divisor trailing zeros */ - while (*divisorend == 0 && divisor_scale > 0) { - divisorend--; - divisor_scale--; - } - while (*divisorend == 0) { - divisorend--; - divisor_int_right_zeros++; - } + const char *numeratorptr = numerator->n_value; + size_t numerator_size = numerator->n_len + quot_scale + divisor->n_scale; - if (*numeratorptr == 0 && numerator_len == 1) { - numeratorptr++; - numerator_len = 0; - } - - size_t numerator_top_extension = 0; - size_t numerator_bottom_extension = 0; - if (divisor_scale > 0) { - /* - * e.g. divisor_scale = 4 - * divisor = .0002, to be 2 or divisor = 200.001, to be 200001 - * numerator = .03, to be 300 or numerator = .000003, to be .03 - * numerator may become longer than the original data length due to the addition of - * trailing zeros in the integer part. - */ - numerator_len += divisor_scale; - numerator_bottom_extension = numerator_scale < divisor_scale ? divisor_scale - numerator_scale : 0; - numerator_scale = numerator_scale > divisor_scale ? numerator_scale - divisor_scale : 0; - divisor_len += divisor_scale; - divisor_scale = 0; - } else if (divisor_int_right_zeros > 0) { - /* - * e.g. divisor_int_right_zeros = 4 - * divisor = 2000, to be 2 - * numerator = 30, to be .03 or numerator = 30000, to be 30 - * Also, numerator may become longer than the original data length due to the addition of - * leading zeros in the fractional part. - */ - numerator_top_extension = numerator_len < divisor_int_right_zeros ? divisor_int_right_zeros - numerator_len : 0; - numerator_len = numerator_len > divisor_int_right_zeros ? numerator_len - divisor_int_right_zeros : 0; - numerator_scale += divisor_int_right_zeros; - divisor_len -= divisor_int_right_zeros; - divisor_scale = 0; - } + const char *divisorptr = divisor->n_value; + size_t divisor_size = divisor->n_len + divisor->n_scale; - /* remove numerator leading zeros */ - while (*numeratorptr == 0 && numerator_len > 0) { + /* check and remove numerator leading zeros */ + size_t numerator_leading_zeros = 0; + while (*numeratorptr == 0) { numeratorptr++; - numerator_len--; + numerator_leading_zeros++; + if (numerator_leading_zeros == numerator_size) { + goto quot_zero; + } } - /* remove divisor leading zeros */ + numerator_size -= numerator_leading_zeros; + + /* check and remove divisor leading zeros */ while (*divisorptr == 0) { divisorptr++; - divisor_len--; + divisor_size--; } - /* Considering the scale specification, the quotient is always 0 if this condition is met */ - if (divisor_len > numerator_len + scale) { - *quot = bc_copy_num(BCG(_zero_)); - return true; + if (divisor_size > numerator_size) { + goto quot_zero; } - /* Length of numerator data that can be read */ - size_t numerator_readable_len = numeratorend - numeratorptr + 1; - - /* set scale to numerator */ - if (numerator_scale > scale) { - size_t scale_diff = numerator_scale - scale; - if (numerator_bottom_extension > scale_diff) { - numerator_bottom_extension -= scale_diff; - } else { - numerator_bottom_extension = 0; - if (EXPECTED(numerator_readable_len > scale_diff)) { - numerator_readable_len -= scale_diff; - numeratorend -= scale_diff; - } else { - numerator_readable_len = 0; - numeratorend = numeratorptr; - } + /* check and remove divisor trailing zeros. The divisor is not 0, so leave only one digit */ + size_t divisor_trailing_zeros = 0; + for (size_t i = divisor_size - 1; i > 0; i--) { + if (divisorptr[i] != 0) { + break; } - numerator_top_extension = MIN(numerator_top_extension, scale); - } else { - numerator_bottom_extension += scale - numerator_scale; + divisor_trailing_zeros++; } - numerator_scale = scale; + divisor_size -= divisor_trailing_zeros; + numerator_size -= divisor_trailing_zeros; - if (divisor_len > numerator_readable_len + numerator_bottom_extension) { - *quot = bc_copy_num(BCG(_zero_)); - return true; + size_t quot_size = numerator_size - divisor_size + 1; /* numerator_size >= divisor_size */ + if (quot_size > quot_scale) { + *quot = bc_new_num_nonzeroed(quot_size - quot_scale, quot_scale); + } else { + *quot = bc_new_num_nonzeroed(1, quot_scale); /* 1 is for 0 */ } - /* If divisor is 1 here, return the result of adjusting the decimal point position of numerator. */ - if (divisor_len == 1 && *divisorptr == 1) { - if (numerator_len == 0) { - numerator_len = 1; - numerator_top_extension++; - } - size_t quot_scale = numerator_scale > numerator_bottom_extension ? numerator_scale - numerator_bottom_extension : 0; - numerator_bottom_extension = numerator_scale < numerator_bottom_extension ? numerator_bottom_extension - numerator_scale : 0; + /* Size that can be read from numeratorptr */ + size_t numerator_readable_size = numerator->n_len + numerator->n_scale - numerator_leading_zeros; - *quot = bc_new_num_nonzeroed(numerator_len, quot_scale); - char *qptr = (*quot)->n_value; - for (size_t i = 0; i < numerator_top_extension; i++) { - *qptr++ = 0; - } - memcpy(qptr, numeratorptr, numerator_readable_len); - qptr += numerator_readable_len; - for (size_t i = 0; i < numerator_bottom_extension; i++) { - *qptr++ = 0; - } + /* If divisor is 1 here, return the result of adjusting the decimal point position of numerator. */ + if (divisor_size == 1 && *divisorptr == 1) { + bc_divide_by_pow_10(numeratorptr, numerator_readable_size, quot, quot_size, quot_scale); (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS; return true; } - size_t quot_full_len; - if (divisor_len > numerator_len) { - *quot = bc_new_num_nonzeroed(1, scale); - quot_full_len = 1 + scale; - } else { - *quot = bc_new_num_nonzeroed(numerator_len - divisor_len + 1, scale); - quot_full_len = numerator_len - divisor_len + 1 + scale; - } - /* do divide */ - bc_do_div(numeratorend, numerator_readable_len, numerator_bottom_extension, divisorend, divisor_len, quot, quot_full_len); + bc_do_div( + numeratorptr, numerator_size, numerator_readable_size, + divisorptr, divisor_size, + quot, quot_size + ); + _bc_rm_leading_zeros(*quot); if (bc_is_zero(*quot)) { (*quot)->n_sign = PLUS; + (*quot)->n_scale = 0; } else { (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS; } + return true; +quot_zero: + *quot = bc_copy_num(BCG(_zero_)); return true; } diff --git a/ext/bcmath/libbcmath/src/divmod.c b/ext/bcmath/libbcmath/src/divmod.c index 294a281b2e687..477ec30e916ea 100644 --- a/ext/bcmath/libbcmath/src/divmod.c +++ b/ext/bcmath/libbcmath/src/divmod.c @@ -74,6 +74,7 @@ bool bc_divmod(bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, size_t scale (*rem)->n_scale = MIN(scale, (*rem)->n_scale); if (bc_is_zero(*rem)) { (*rem)->n_sign = PLUS; + (*rem)->n_scale = 0; } return true; diff --git a/ext/bcmath/libbcmath/src/doaddsub.c b/ext/bcmath/libbcmath/src/doaddsub.c index feb50120c70c3..f516f2bda72df 100644 --- a/ext/bcmath/libbcmath/src/doaddsub.c +++ b/ext/bcmath/libbcmath/src/doaddsub.c @@ -46,7 +46,7 @@ bc_num _bc_do_add(bc_num n1, bc_num n2) size_t min_len = MIN (n1->n_len, n2->n_len); size_t min_scale = MIN(n1->n_scale, n2->n_scale); size_t min_bytes = min_len + min_scale; - char *n1ptr, *n2ptr, *sumptr; + char *sumptr; bool carry = 0; size_t count; @@ -54,8 +54,8 @@ bc_num _bc_do_add(bc_num n1, bc_num n2) sum = bc_new_num_nonzeroed(sum_len, sum_scale); /* Start with the fraction part. Initialize the pointers. */ - n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale - 1); - n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale - 1); + const char *n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale - 1); + const char *n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale - 1); sumptr = (char *) (sum->n_value + sum_scale + sum_len - 1); /* Add the fraction part. First copy the longer fraction.*/ @@ -182,14 +182,14 @@ bc_num _bc_do_sub(bc_num n1, bc_num n2) size_t borrow = 0; size_t count; int val; - char *n1ptr, *n2ptr, *diffptr; + char *diffptr; /* Allocate temporary storage. */ diff = bc_new_num_nonzeroed(diff_len, diff_scale); /* Initialize the subtract. */ - n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale - 1); - n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale - 1); + const char *n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale - 1); + const char *n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale - 1); diffptr = (char *) (diff->n_value + diff_len + diff_scale - 1); /* Take care of the longer scaled number. */ diff --git a/ext/bcmath/libbcmath/src/private.h b/ext/bcmath/libbcmath/src/private.h index 5c0087901a4a2..91facfb2f8b40 100644 --- a/ext/bcmath/libbcmath/src/private.h +++ b/ext/bcmath/libbcmath/src/private.h @@ -35,6 +35,9 @@ #include #include "zend_portability.h" +#ifndef _BCMATH_PRIV_H_ +#define _BCMATH_PRIV_H_ + /* This will be 0x01010101 for 32-bit and 0x0101010101010101 for 64-bit */ #define SWAR_ONES (~((size_t) 0) / 0xFF) /* This repeats a byte `x` into an entire 32/64-bit word. @@ -61,15 +64,26 @@ # define BC_LITTLE_ENDIAN 1 #endif +/* 64-bytes for 64-bit */ +#define BC_STACK_VECTOR_SIZE 8 + +#define BC_ARR_SIZE_FROM_LEN(len) (((len) + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE) + /* * Adding more than this many times may cause uint32_t/uint64_t to overflow. * Typically this is 1844 for 64bit and 42 for 32bit. */ #define BC_VECTOR_NO_OVERFLOW_ADD_COUNT (~((BC_VECTOR) 0) / (BC_VECTOR_BOUNDARY_NUM * BC_VECTOR_BOUNDARY_NUM)) +static const BC_VECTOR BC_POW_10_LUT[9] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 +}; + /* routines */ bcmath_compare_result _bc_do_compare (bc_num n1, bc_num n2, size_t scale, bool use_sign); bc_num _bc_do_add (bc_num n1, bc_num n2); bc_num _bc_do_sub (bc_num n1, bc_num n2); void _bc_rm_leading_zeros (bc_num num); + +#endif diff --git a/ext/bcmath/libbcmath/src/recmul.c b/ext/bcmath/libbcmath/src/recmul.c index b92a1045ac3b5..26ce1641db410 100644 --- a/ext/bcmath/libbcmath/src/recmul.c +++ b/ext/bcmath/libbcmath/src/recmul.c @@ -107,27 +107,8 @@ static inline void bc_mul_finish_from_vector(BC_VECTOR *prod_vector, size_t prod *prod = bc_new_num_nonzeroed(prodlen, 0); char *pptr = (*prod)->n_value; char *pend = pptr + prodlen - 1; - size_t i = 0; - while (i < prod_arr_size - 1) { -#if BC_VECTOR_SIZE == 4 - bc_write_bcd_representation(prod_vector[i], pend - 3); - pend -= 4; -#else - bc_write_bcd_representation(prod_vector[i] / 10000, pend - 7); - bc_write_bcd_representation(prod_vector[i] % 10000, pend - 3); - pend -= 8; -#endif - i++; - } - /* - * The last digit may carry over. - * Also need to fill it to the end with zeros, so loop until the end of the string. - */ - while (pend >= pptr) { - *pend-- = prod_vector[i] % BASE; - prod_vector[i] /= BASE; - } + bc_convert_vector_to_char(prod_vector, pptr, pend, prod_arr_size); } /* @@ -145,19 +126,25 @@ static void bc_standard_mul(bc_num n1, size_t n1len, bc_num n2, size_t n2len, bc const char *n2end = n2->n_value + n2len - 1; size_t prodlen = n1len + n2len; - size_t n1_arr_size = (n1len + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE; - size_t n2_arr_size = (n2len + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE; - size_t prod_arr_size = (prodlen + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE; + size_t n1_arr_size = BC_ARR_SIZE_FROM_LEN(n1len); + size_t n2_arr_size = BC_ARR_SIZE_FROM_LEN(n2len); + size_t prod_arr_size = BC_ARR_SIZE_FROM_LEN(prodlen); - /* - * let's say that N is the max of n1len and n2len (and a multiple of BC_VECTOR_SIZE for simplicity), - * then this sum is <= N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE - 1 - * which is equal to N - 1 if BC_VECTOR_SIZE is 4, and N/2 - 1 if BC_VECTOR_SIZE is 8. - */ - BC_VECTOR *buf = safe_emalloc(n1_arr_size + n2_arr_size + prod_arr_size, sizeof(BC_VECTOR), 0); + BC_VECTOR stack_vectors[BC_STACK_VECTOR_SIZE]; + size_t allocation_arr_size = n1_arr_size + n2_arr_size + prod_arr_size; - BC_VECTOR *n1_vector = buf; - BC_VECTOR *n2_vector = buf + n1_arr_size; + BC_VECTOR *n1_vector; + if (allocation_arr_size <= BC_STACK_VECTOR_SIZE) { + n1_vector = stack_vectors; + } else { + /* + * let's say that N is the max of n1len and n2len (and a multiple of BC_VECTOR_SIZE for simplicity), + * then this sum is <= N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE + N/BC_VECTOR_SIZE - 1 + * which is equal to N - 1 if BC_VECTOR_SIZE is 4, and N/2 - 1 if BC_VECTOR_SIZE is 8. + */ + n1_vector = safe_emalloc(allocation_arr_size, sizeof(BC_VECTOR), 0); + } + BC_VECTOR *n2_vector = n1_vector + n1_arr_size; BC_VECTOR *prod_vector = n2_vector + n2_arr_size; for (i = 0; i < prod_arr_size; i++) { @@ -188,7 +175,9 @@ static void bc_standard_mul(bc_num n1, size_t n1len, bc_num n2, size_t n2len, bc bc_mul_finish_from_vector(prod_vector, prod_arr_size, prodlen, prod); - efree(buf); + if (allocation_arr_size > BC_STACK_VECTOR_SIZE) { + efree(n1_vector); + } } /** This is bc_standard_mul implementation for square */ @@ -198,8 +187,8 @@ static void bc_standard_square(bc_num n1, size_t n1len, bc_num *prod) const char *n1end = n1->n_value + n1len - 1; size_t prodlen = n1len + n1len; - size_t n1_arr_size = (n1len + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE; - size_t prod_arr_size = (prodlen + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE; + size_t n1_arr_size = BC_ARR_SIZE_FROM_LEN(n1len); + size_t prod_arr_size = BC_ARR_SIZE_FROM_LEN(prodlen); BC_VECTOR *buf = safe_emalloc(n1_arr_size + n1_arr_size + prod_arr_size, sizeof(BC_VECTOR), 0); @@ -264,6 +253,7 @@ bc_num bc_multiply(bc_num n1, bc_num n2, size_t scale) _bc_rm_leading_zeros(prod); if (bc_is_zero(prod)) { prod->n_sign = PLUS; + prod->n_scale = 0; } return prod; } diff --git a/ext/bcmath/libbcmath/src/round.c b/ext/bcmath/libbcmath/src/round.c index ac3c7c41a315e..44df6036cbe3b 100644 --- a/ext/bcmath/libbcmath/src/round.c +++ b/ext/bcmath/libbcmath/src/round.c @@ -18,7 +18,8 @@ #include "private.h" #include -void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) +/* Returns the scale of the value after rounding. */ +size_t bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) { /* clear result */ bc_free_num(result); @@ -43,19 +44,19 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) case PHP_ROUND_HALF_ODD: case PHP_ROUND_TOWARD_ZERO: *result = bc_copy_num(BCG(_zero_)); - return; + return 0; case PHP_ROUND_CEILING: if (num->n_sign == MINUS) { *result = bc_copy_num(BCG(_zero_)); - return; + return 0; } break; case PHP_ROUND_FLOOR: if (num->n_sign == PLUS) { *result = bc_copy_num(BCG(_zero_)); - return; + return 0; } break; @@ -67,7 +68,7 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) if (bc_is_zero(num)) { *result = bc_copy_num(BCG(_zero_)); - return; + return 0; } /* If precision is -3, it becomes 1000. */ @@ -78,7 +79,7 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) } (*result)->n_value[0] = 1; (*result)->n_sign = num->n_sign; - return; + return 0; } /* Just like bcadd('1', '1', 4) becomes '2.0000', it pads with zeros at the end if necessary. */ @@ -90,7 +91,7 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) (*result)->n_sign = num->n_sign; memcpy((*result)->n_value, num->n_value, num->n_len + num->n_scale); } - return; + return precision; } /* @@ -222,7 +223,12 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) } check_zero: - if (bc_is_zero(*result)) { - (*result)->n_sign = PLUS; + { + size_t scale = (*result)->n_scale; + if (bc_is_zero(*result)) { + (*result)->n_sign = PLUS; + (*result)->n_scale = 0; + } + return scale; } } diff --git a/ext/bcmath/libbcmath/src/simd.h b/ext/bcmath/libbcmath/src/simd.h new file mode 100644 index 0000000000000..af38f8349618c --- /dev/null +++ b/ext/bcmath/libbcmath/src/simd.h @@ -0,0 +1,59 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Saki Takamachi | + +----------------------------------------------------------------------+ +*/ + + +#ifndef _BCMATH_SIMD_H_ +#define _BCMATH_SIMD_H_ + +#ifdef __SSE2__ +# include + typedef __m128i bc_simd_128_t; +# define HAVE_BC_SIMD_128 +# define bc_simd_set_8x16(x) _mm_set1_epi8(x) +# define bc_simd_load_8x16(ptr) _mm_loadu_si128((const __m128i *) (ptr)) +# define bc_simd_xor_8x16(a, b) _mm_xor_si128(a, b) +# define bc_simd_store_8x16(ptr, val) _mm_storeu_si128((__m128i *) (ptr), val) +# define bc_simd_add_8x16(a, b) _mm_add_epi8(a, b) +# define bc_simd_cmpeq_8x16(a, b) _mm_cmpeq_epi8(a, b) +# define bc_simd_cmplt_8x16(a, b) _mm_cmplt_epi8(a, b) +# define bc_simd_movemask_8x16(a) _mm_movemask_epi8(a) + +#elif defined(__aarch64__) || defined(_M_ARM64) +# include + typedef int8x16_t bc_simd_128_t; +# define HAVE_BC_SIMD_128 +# define bc_simd_set_8x16(x) vdupq_n_s8(x) +# define bc_simd_load_8x16(ptr) vld1q_s8((const int8_t *) (ptr)) +# define bc_simd_xor_8x16(a, b) veorq_s8(a, b) +# define bc_simd_store_8x16(ptr, val) vst1q_s8((int8_t *) (ptr), val) +# define bc_simd_add_8x16(a, b) vaddq_s8(a, b) +# define bc_simd_cmpeq_8x16(a, b) (vreinterpretq_s8_u8(vceqq_s8(a, b))) +# define bc_simd_cmplt_8x16(a, b) (vreinterpretq_s8_u8(vcltq_s8(a, b))) + static inline int bc_simd_movemask_8x16(int8x16_t vec) + { + /** + * based on code from + * https://community.arm.com/arm-community-blogs/b/servers-and-cloud-computing-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon + */ + uint16x8_t high_bits = vreinterpretq_u16_u8(vshrq_n_u8(vreinterpretq_u8_s8(vec), 7)); + uint32x4_t paired16 = vreinterpretq_u32_u16(vsraq_n_u16(high_bits, high_bits, 7)); + uint64x2_t paired32 = vreinterpretq_u64_u32(vsraq_n_u32(paired16, paired16, 14)); + uint8x16_t paired64 = vreinterpretq_u8_u64(vsraq_n_u64(paired32, paired32, 28)); + return vgetq_lane_u8(paired64, 0) | ((int) vgetq_lane_u8(paired64, 8) << 8); + } +#endif + +#endif diff --git a/ext/bcmath/libbcmath/src/str2num.c b/ext/bcmath/libbcmath/src/str2num.c index 79c1d4216fe7b..945de0cf60003 100644 --- a/ext/bcmath/libbcmath/src/str2num.c +++ b/ext/bcmath/libbcmath/src/str2num.c @@ -32,30 +32,28 @@ #include "bcmath.h" #include "convert.h" #include "private.h" +#include "simd.h" #include #include -#ifdef __SSE2__ -# include -#endif /* Convert strings to bc numbers. Base 10 only.*/ -static const char *bc_count_digits(const char *str, const char *end) +static inline const char *bc_count_digits(const char *str, const char *end) { /* Process in bulk */ -#ifdef __SSE2__ - const __m128i offset = _mm_set1_epi8((signed char) (SCHAR_MIN - '0')); +#ifdef HAVE_BC_SIMD_128 + const bc_simd_128_t offset = bc_simd_set_8x16((signed char) (SCHAR_MIN - '0')); /* we use the less than comparator, so add 1 */ - const __m128i threshold = _mm_set1_epi8(SCHAR_MIN + ('9' + 1 - '0')); + const bc_simd_128_t threshold = bc_simd_set_8x16(SCHAR_MIN + ('9' + 1 - '0')); - while (str + sizeof(__m128i) <= end) { - __m128i bytes = _mm_loadu_si128((const __m128i *) str); + while (str + sizeof(bc_simd_128_t) <= end) { + bc_simd_128_t bytes = bc_simd_load_8x16((const bc_simd_128_t *) str); /* Wrapping-add the offset to the bytes, such that all bytes below '0' are positive and others are negative. * More specifically, '0' will be -128 and '9' will be -119. */ - bytes = _mm_add_epi8(bytes, offset); + bytes = bc_simd_add_8x16(bytes, offset); /* Now mark all bytes that are <= '9', i.e. <= -119, i.e. < -118, i.e. the threshold. */ - bytes = _mm_cmplt_epi8(bytes, threshold); + bytes = bc_simd_cmplt_8x16(bytes, threshold); - int mask = _mm_movemask_epi8(bytes); + int mask = bc_simd_movemask_8x16(bytes); if (mask != 0xffff) { /* At least one of the bytes is not within range. Move to the first offending byte. */ #ifdef PHP_HAVE_BUILTIN_CTZL @@ -65,7 +63,7 @@ static const char *bc_count_digits(const char *str, const char *end) #endif } - str += sizeof(__m128i); + str += sizeof(bc_simd_128_t); } #endif @@ -79,19 +77,19 @@ static const char *bc_count_digits(const char *str, const char *end) static inline const char *bc_skip_zero_reverse(const char *scanner, const char *stop) { /* Check in bulk */ -#ifdef __SSE2__ - const __m128i c_zero_repeat = _mm_set1_epi8('0'); - while (scanner - sizeof(__m128i) >= stop) { - scanner -= sizeof(__m128i); - __m128i bytes = _mm_loadu_si128((const __m128i *) scanner); +#ifdef HAVE_BC_SIMD_128 + const bc_simd_128_t c_zero_repeat = bc_simd_set_8x16('0'); + while (scanner - sizeof(bc_simd_128_t) >= stop) { + scanner -= sizeof(bc_simd_128_t); + bc_simd_128_t bytes = bc_simd_load_8x16((const bc_simd_128_t *) scanner); /* Checks if all numeric strings are equal to '0'. */ - bytes = _mm_cmpeq_epi8(bytes, c_zero_repeat); + bytes = bc_simd_cmpeq_8x16(bytes, c_zero_repeat); - int mask = _mm_movemask_epi8(bytes); + int mask = bc_simd_movemask_8x16(bytes); /* The probability of having 16 trailing 0s in a row is very low, so we use EXPECTED. */ if (EXPECTED(mask != 0xffff)) { /* Move the pointer back and check each character in loop. */ - scanner += sizeof(__m128i); + scanner += sizeof(bc_simd_128_t); break; } } @@ -180,7 +178,7 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, siz */ if (str_scale > 0) { const char *fractional_new_end = bc_skip_zero_reverse(fractional_end, fractional_ptr); - str_scale -= fractional_new_end - fractional_end; + str_scale -= fractional_end - fractional_new_end; /* fractional_end >= fractional_new_end */ } } } else { diff --git a/ext/bz2/tests/004.phpt b/ext/bz2/tests/004.phpt index e644bfa6ce962..240cef37a17a2 100644 --- a/ext/bz2/tests/004.phpt +++ b/ext/bz2/tests/004.phpt @@ -112,8 +112,8 @@ array(2) { } string(10) "DATA_ERROR" int(-4) -bzread(): supplied resource is not a valid stream resource -bzerror(): supplied resource is not a valid stream resource -bzerrstr(): supplied resource is not a valid stream resource -bzerrno(): supplied resource is not a valid stream resource +bzread(): Argument #1 ($bz) must be an open stream resource +bzerror(): Argument #1 ($bz) must be an open stream resource +bzerrstr(): Argument #1 ($bz) must be an open stream resource +bzerrno(): Argument #1 ($bz) must be an open stream resource Done diff --git a/ext/calendar/calendar.c b/ext/calendar/calendar.c index a0503dab0600f..0f9a4b99a37bc 100644 --- a/ext/calendar/calendar.c +++ b/ext/calendar/calendar.c @@ -131,8 +131,10 @@ static void _php_cal_info(int cal, zval *ret) calendar = &cal_conversion_table[cal]; array_init(ret); - array_init(&months); - array_init(&smonths); + array_init_size(&months, calendar->num_months + 1); + array_init_size(&smonths, calendar->num_months + 1); + zend_hash_real_init_packed(Z_ARRVAL(months)); + zend_hash_real_init_packed(Z_ARRVAL(smonths)); for (i = 1; i <= calendar->num_months; i++) { add_index_string(&months, i, calendar->month_name_long[i]); @@ -160,7 +162,8 @@ PHP_FUNCTION(cal_info) int i; zval val; - array_init(return_value); + array_init_size(return_value, CAL_NUM_CALS); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for (i = 0; i < CAL_NUM_CALS; i++) { _php_cal_info(i, &val); diff --git a/ext/curl/curl.stub.php b/ext/curl/curl.stub.php index c9abe237339b5..6a73913f8a85e 100644 --- a/ext/curl/curl.stub.php +++ b/ext/curl/curl.stub.php @@ -188,6 +188,11 @@ * @cvalue CURLOPT_INFILESIZE */ const CURLOPT_INFILESIZE = UNKNOWN; +/** + * @var int + * @cvalue CURLOPT_INFILESIZE_LARGE + */ +const CURLOPT_INFILESIZE_LARGE = UNKNOWN; /** * @var int * @cvalue CURLOPT_INTERFACE diff --git a/ext/curl/curl_arginfo.h b/ext/curl/curl_arginfo.h index 6a81d1e92c88f..53a59fe47be49 100644 --- a/ext/curl/curl_arginfo.h +++ b/ext/curl/curl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 48fc95503f4f8cc96575ff6f31fdd1e4cdc5969e */ + * Stub hash: 77da3a34f08b3e932a0545f72b41bf0353e8b157 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_curl_close, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, handle, CurlHandle, 0) @@ -263,6 +263,7 @@ static void register_curl_symbols(int module_number) REGISTER_LONG_CONSTANT("CURLOPT_HTTP_VERSION", CURLOPT_HTTP_VERSION, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURLOPT_INFILE", CURLOPT_INFILE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURLOPT_INFILESIZE", CURLOPT_INFILESIZE, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("CURLOPT_INFILESIZE_LARGE", CURLOPT_INFILESIZE_LARGE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURLOPT_INTERFACE", CURLOPT_INTERFACE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURLOPT_KRB4LEVEL", CURLOPT_KRB4LEVEL, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURLOPT_LOW_SPEED_LIMIT", CURLOPT_LOW_SPEED_LIMIT, CONST_PERSISTENT); diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 311b2f7cc8a59..a087da78c37e4 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -546,7 +546,9 @@ static HashTable *curl_get_gc(zend_object *object, zval **table, int *n) zend_get_gc_buffer_use(gc_buffer, table, n); - return zend_std_get_properties(object); + /* CurlHandle can never have properties as it's final and has strict-properties on. + * Avoid building a hash table. */ + return NULL; } zend_result curl_cast_object(zend_object *obj, zval *result, int type) @@ -843,7 +845,7 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx) { php_curl *ch = (php_curl *)ctx; php_curl_read *read_handler = ch->handlers.read; - int length = 0; + size_t length = 0; switch (read_handler->method) { case PHP_CURL_DIRECT: @@ -1184,7 +1186,6 @@ static void create_certinfo(struct curl_certinfo *ci, zval *listcode) array_init(&certhash); for (slist = ci->certinfo[i]; slist; slist = slist->next) { - int len; char s[64]; char *tmp; strncpy(s, slist->data, sizeof(s)); @@ -1192,7 +1193,7 @@ static void create_certinfo(struct curl_certinfo *ci, zval *listcode) tmp = memchr(s, ':', sizeof(s)); if(tmp) { *tmp = '\0'; - len = strlen(s); + size_t len = strlen(s); add_assoc_string(&certhash, s, &slist->data[len+1]); } else { php_error_docref(NULL, E_WARNING, "Could not extract hash key from certificate info"); @@ -1445,7 +1446,6 @@ static inline zend_result build_mime_structure_from_hash(php_curl *ch, zval *zpo zval *prop, rv; char *type = NULL, *filename = NULL; struct mime_data_cb_arg *cb_arg; - php_stream *stream; php_stream_statbuf ssb; size_t filesize = -1; curl_seek_callback seekfunc = seek_cb; @@ -1475,6 +1475,7 @@ static inline zend_result build_mime_structure_from_hash(php_curl *ch, zval *zpo zval_ptr_dtor(&ch->postfields); ZVAL_COPY(&ch->postfields, zpostfields); + php_stream *stream; if ((stream = php_stream_open_wrapper(ZSTR_VAL(postval), "rb", STREAM_MUST_SEEK, NULL))) { if (!stream->readfilters.head && !php_stream_stat(stream, &ssb)) { filesize = ssb.sb.st_size; @@ -2243,6 +2244,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue break; /* Curl off_t options */ + case CURLOPT_INFILESIZE_LARGE: case CURLOPT_MAX_RECV_SPEED_LARGE: case CURLOPT_MAX_SEND_SPEED_LARGE: case CURLOPT_MAXFILESIZE_LARGE: @@ -2409,7 +2411,7 @@ PHP_FUNCTION(curl_setopt_array) ch = Z_CURL_P(zid); ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(arr), option, string_key, entry) { - if (string_key) { + if (UNEXPECTED(string_key)) { zend_argument_value_error(2, "contains an invalid cURL option"); RETURN_THROWS(); } @@ -2745,6 +2747,7 @@ PHP_FUNCTION(curl_getinfo) if (curl_easy_getinfo(ch->cp, option, &slist) == CURLE_OK) { struct curl_slist *current = slist; array_init(return_value); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); while (current) { add_next_index_string(return_value, current->data); current = current->next; diff --git a/ext/curl/multi.c b/ext/curl/multi.c index 938393f410e70..f664bc05e0e89 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -185,7 +185,8 @@ PHP_FUNCTION(curl_multi_get_handles) mh = Z_CURL_MULTI_P(z_mh); - array_init(return_value); + array_init_size(return_value, zend_llist_count(&mh->easyh)); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); zend_llist_position pos; zval *pz_ch; @@ -403,7 +404,7 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea php_curl *ch; php_curl *parent; php_curlm *mh = (php_curlm *)userp; - size_t rval = CURL_PUSH_DENY; + int rval = CURL_PUSH_DENY; zval *pz_parent_ch = NULL; zval pz_ch; zval headers; @@ -420,10 +421,11 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea ch->cp = easy; _php_setup_easy_copy_handlers(ch, parent); - array_init(&headers); + array_init_size(&headers, num_headers); + zend_hash_real_init_packed(Z_ARRVAL(headers)); for (size_t i = 0; i < num_headers; i++) { char *header = curl_pushheader_bynum(push_headers, i); - add_next_index_string(&headers, header); + add_index_string(&headers, i, header); } ZEND_ASSERT(pz_parent_ch); @@ -524,11 +526,7 @@ PHP_FUNCTION(curl_multi_setopt) mh = Z_CURL_MULTI_P(z_mh); - if (_php_curl_multi_setopt(mh, options, zvalue, return_value)) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(_php_curl_multi_setopt(mh, options, zvalue, return_value)); } /* }}} */ @@ -598,7 +596,9 @@ static HashTable *curl_multi_get_gc(zend_object *object, zval **table, int *n) zend_get_gc_buffer_use(gc_buffer, table, n); - return zend_std_get_properties(object); + /* CurlMultiHandle can never have properties as it's final and has strict-properties on. + * Avoid building a hash table. */ + return NULL; } static zend_object_handlers curl_multi_handlers; diff --git a/ext/curl/share.c b/ext/curl/share.c index 8f3bb7543a20f..e5f9e3d807dc2 100644 --- a/ext/curl/share.c +++ b/ext/curl/share.c @@ -54,7 +54,7 @@ PHP_FUNCTION(curl_share_close) } /* }}} */ -static bool _php_curl_share_setopt(php_curlsh *sh, zend_long option, zval *zvalue, zval *return_value) /* {{{ */ +static bool _php_curl_share_setopt(php_curlsh *sh, zend_long option, const zval *zvalue) /* {{{ */ { CURLSHcode error = CURLSHE_OK; @@ -91,11 +91,7 @@ PHP_FUNCTION(curl_share_setopt) sh = Z_CURL_SHARE_P(z_sh); - if (_php_curl_share_setopt(sh, options, zvalue, return_value)) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(_php_curl_share_setopt(sh, options, zvalue)); } /* }}} */ diff --git a/ext/curl/tests/Caddyfile b/ext/curl/tests/Caddyfile index 30686f0bb9fa2..67b82434ba4c6 100644 --- a/ext/curl/tests/Caddyfile +++ b/ext/curl/tests/Caddyfile @@ -12,6 +12,11 @@ respond /serverpush "main response" respond /serverpush/pushed "pushed response" push /serverpush /serverpush/pushed +route /show_upload_size { + templates + respond `Content-length: ={{.Req.Header.Get "Content-length"}}=` +} + basic_auth /http-basic-auth { # bcrypt password hash for "password", calculated with 'caddy hash-password' user $2a$14$yUKl9SGqVTAAqPTzLup.DefsbXXx3kfreNnzpJOUHcIrKnr5lgef2 diff --git a/ext/curl/tests/curl_setopt_CURLOPT_INFILESIZE_LARGE.phpt b/ext/curl/tests/curl_setopt_CURLOPT_INFILESIZE_LARGE.phpt new file mode 100644 index 0000000000000..5063958412b5a --- /dev/null +++ b/ext/curl/tests/curl_setopt_CURLOPT_INFILESIZE_LARGE.phpt @@ -0,0 +1,58 @@ +--TEST-- +Curl option CURLOPT_INFILESIZE_LARGE +--EXTENSIONS-- +curl +--SKIPIF-- + +--FILE-- + true, + CURLOPT_UPLOAD => true, + CURLOPT_INFILE => $f, + CURLOPT_INFILESIZE => filesize(__FILE__), + CURLOPT_CONNECTTIMEOUT => 3, + CURLOPT_TIMEOUT => 3, + CURLOPT_SSL_VERIFYHOST => 0, + CURLOPT_SSL_VERIFYPEER => 0, +])); + +var_dump(curl_exec($ch)); + +var_dump(curl_setopt($ch, CURLOPT_INFILESIZE, -1)); +var_dump(curl_exec($ch)); + +var_dump(curl_setopt($ch, CURLOPT_INFILESIZE_LARGE, -1)); +var_dump(curl_exec($ch)); + +rewind($f); +var_dump(curl_setopt($ch, CURLOPT_INFILESIZE, filesize(__FILE__))); +var_dump(curl_exec($ch)); +var_dump(curl_setopt($ch, CURLOPT_INFILESIZE_LARGE, -1)); +var_dump(curl_exec($ch)); + +rewind($f); +var_dump(curl_setopt($ch, CURLOPT_INFILESIZE_LARGE, filesize(__FILE__))); +var_dump(curl_exec($ch)); + +var_dump(curl_error($ch)); + +?> +--EXPECTF-- +bool(true) +string(21) "Content-length: =%d=" +bool(true) +string(18) "Content-length: ==" +bool(true) +string(18) "Content-length: ==" +bool(true) +string(21) "Content-length: =%d=" +bool(true) +string(18) "Content-length: ==" +bool(true) +string(21) "Content-length: =%d=" +string(0) "" diff --git a/ext/date/lib/timezonedb.h b/ext/date/lib/timezonedb.h index 3c75462009afb..a4cbb618799c8 100644 --- a/ext/date/lib/timezonedb.h +++ b/ext/date/lib/timezonedb.h @@ -4,7 +4,7 @@ #endif #ifdef TIMELIB_SUPPORT_SLIM_FILE -const timelib_tzdb_index_entry timezonedb_idx_builtin[597] = { +const timelib_tzdb_index_entry timezonedb_idx_builtin[598] = { { (char*) "Africa/Abidjan" , 0x000000 }, { (char*) "Africa/Accra" , 0x00008E }, { (char*) "Africa/Addis_Ababa" , 0x000356 }, @@ -104,508 +104,509 @@ const timelib_tzdb_index_entry timezonedb_idx_builtin[597] = { { (char*) "America/Coral_Harbour" , 0x00ADD3 }, { (char*) "America/Cordoba" , 0x00AE74 }, { (char*) "America/Costa_Rica" , 0x00B144 }, - { (char*) "America/Creston" , 0x00B238 }, - { (char*) "America/Cuiaba" , 0x00B2F4 }, - { (char*) "America/Curacao" , 0x00B6B1 }, - { (char*) "America/Danmarkshavn" , 0x00B754 }, - { (char*) "America/Dawson" , 0x00B939 }, - { (char*) "America/Dawson_Creek" , 0x00BD5C }, - { (char*) "America/Denver" , 0x00C033 }, - { (char*) "America/Detroit" , 0x00C466 }, - { (char*) "America/Dominica" , 0x00C80E }, - { (char*) "America/Edmonton" , 0x00C89C }, - { (char*) "America/Eirunepe" , 0x00CC94 }, - { (char*) "America/El_Salvador" , 0x00CE63 }, - { (char*) "America/Ensenada" , 0x00CF1F }, - { (char*) "America/Fort_Nelson" , 0x00D362 }, - { (char*) "America/Fort_Wayne" , 0x00D92A }, - { (char*) "America/Fortaleza" , 0x00DB49 }, - { (char*) "America/Glace_Bay" , 0x00DD5F }, - { (char*) "America/Godthab" , 0x00E0F6 }, - { (char*) "America/Goose_Bay" , 0x00E4C7 }, - { (char*) "America/Grand_Turk" , 0x00EB1F }, - { (char*) "America/Grenada" , 0x00EE80 }, - { (char*) "America/Guadeloupe" , 0x00EF0E }, - { (char*) "America/Guatemala" , 0x00EF9C }, - { (char*) "America/Guayaquil" , 0x00F07C }, - { (char*) "America/Guyana" , 0x00F14D }, - { (char*) "America/Halifax" , 0x00F20E }, - { (char*) "America/Havana" , 0x00F8C0 }, - { (char*) "America/Hermosillo" , 0x00FD29 }, - { (char*) "America/Indiana/Indianapolis" , 0x00FE3D }, - { (char*) "America/Indiana/Knox" , 0x010075 }, - { (char*) "America/Indiana/Marengo" , 0x01048E }, - { (char*) "America/Indiana/Petersburg" , 0x0106E8 }, - { (char*) "America/Indiana/Tell_City" , 0x0109B2 }, - { (char*) "America/Indiana/Vevay" , 0x010BDC }, - { (char*) "America/Indiana/Vincennes" , 0x010D73 }, - { (char*) "America/Indiana/Winamac" , 0x010FC9 }, - { (char*) "America/Indianapolis" , 0x011246 }, - { (char*) "America/Inuvik" , 0x011465 }, - { (char*) "America/Iqaluit" , 0x0117B6 }, - { (char*) "America/Jamaica" , 0x011B32 }, - { (char*) "America/Jujuy" , 0x011C91 }, - { (char*) "America/Juneau" , 0x011F4F }, - { (char*) "America/Kentucky/Louisville" , 0x012335 }, - { (char*) "America/Kentucky/Monticello" , 0x012839 }, - { (char*) "America/Knox_IN" , 0x012C25 }, - { (char*) "America/Kralendijk" , 0x013029 }, - { (char*) "America/La_Paz" , 0x0130E6 }, - { (char*) "America/Lima" , 0x01319C }, - { (char*) "America/Los_Angeles" , 0x0132C3 }, - { (char*) "America/Louisville" , 0x0137E4 }, - { (char*) "America/Lower_Princes" , 0x013CCA }, - { (char*) "America/Maceio" , 0x013D87 }, - { (char*) "America/Managua" , 0x013F99 }, - { (char*) "America/Manaus" , 0x0140CC }, - { (char*) "America/Marigot" , 0x014283 }, - { (char*) "America/Martinique" , 0x014340 }, - { (char*) "America/Matamoros" , 0x0143FE }, - { (char*) "America/Mazatlan" , 0x0145EB }, - { (char*) "America/Mendoza" , 0x0148DB }, - { (char*) "America/Menominee" , 0x014BAB }, - { (char*) "America/Merida" , 0x014F6B }, - { (char*) "America/Metlakatla" , 0x015216 }, - { (char*) "America/Mexico_City" , 0x015483 }, - { (char*) "America/Miquelon" , 0x0157A2 }, - { (char*) "America/Moncton" , 0x0159D4 }, - { (char*) "America/Monterrey" , 0x015FCD }, - { (char*) "America/Montevideo" , 0x0162D4 }, - { (char*) "America/Montreal" , 0x0166A9 }, - { (char*) "America/Montserrat" , 0x016D6A }, - { (char*) "America/Nassau" , 0x016DF8 }, - { (char*) "America/New_York" , 0x0171F2 }, - { (char*) "America/Nipigon" , 0x0178E2 }, - { (char*) "America/Nome" , 0x017FA3 }, - { (char*) "America/Noronha" , 0x01838B }, - { (char*) "America/North_Dakota/Beulah" , 0x01858B }, - { (char*) "America/North_Dakota/Center" , 0x0189BF }, - { (char*) "America/North_Dakota/New_Salem" , 0x018DBE }, - { (char*) "America/Nuuk" , 0x0191C3 }, - { (char*) "America/Ojinaga" , 0x0195A5 }, - { (char*) "America/Panama" , 0x01989B }, - { (char*) "America/Pangnirtung" , 0x01993C }, - { (char*) "America/Paramaribo" , 0x019C9F }, - { (char*) "America/Phoenix" , 0x019D66 }, - { (char*) "America/Port-au-Prince" , 0x019E7A }, - { (char*) "America/Port_of_Spain" , 0x01A0BB }, - { (char*) "America/Porto_Acre" , 0x01A149 }, - { (char*) "America/Porto_Velho" , 0x01A2F7 }, - { (char*) "America/Puerto_Rico" , 0x01A495 }, - { (char*) "America/Punta_Arenas" , 0x01A552 }, - { (char*) "America/Rainy_River" , 0x01AA34 }, - { (char*) "America/Rankin_Inlet" , 0x01AF4E }, - { (char*) "America/Recife" , 0x01B297 }, - { (char*) "America/Regina" , 0x01B491 }, - { (char*) "America/Resolute" , 0x01B730 }, - { (char*) "America/Rio_Branco" , 0x01BA7A }, - { (char*) "America/Rosario" , 0x01BC2C }, - { (char*) "America/Santa_Isabel" , 0x01BEFC }, - { (char*) "America/Santarem" , 0x01C33F }, - { (char*) "America/Santiago" , 0x01C4EF }, - { (char*) "America/Santo_Domingo" , 0x01CA52 }, - { (char*) "America/Sao_Paulo" , 0x01CB9B }, - { (char*) "America/Scoresbysund" , 0x01CF95 }, - { (char*) "America/Shiprock" , 0x01D396 }, - { (char*) "America/Sitka" , 0x01D7B4 }, - { (char*) "America/St_Barthelemy" , 0x01DB8F }, - { (char*) "America/St_Johns" , 0x01DC4C }, - { (char*) "America/St_Kitts" , 0x01E3C9 }, - { (char*) "America/St_Lucia" , 0x01E457 }, - { (char*) "America/St_Thomas" , 0x01E4F8 }, - { (char*) "America/St_Vincent" , 0x01E586 }, - { (char*) "America/Swift_Current" , 0x01E627 }, - { (char*) "America/Tegucigalpa" , 0x01E7B5 }, - { (char*) "America/Thule" , 0x01E883 }, - { (char*) "America/Thunder_Bay" , 0x01EA64 }, - { (char*) "America/Tijuana" , 0x01F125 }, - { (char*) "America/Toronto" , 0x01F577 }, - { (char*) "America/Tortola" , 0x01FC56 }, - { (char*) "America/Vancouver" , 0x01FCE4 }, - { (char*) "America/Virgin" , 0x02023B }, - { (char*) "America/Whitehorse" , 0x0202F8 }, - { (char*) "America/Winnipeg" , 0x02071B }, - { (char*) "America/Yakutat" , 0x020C52 }, - { (char*) "America/Yellowknife" , 0x021020 }, - { (char*) "Antarctica/Casey" , 0x0213F6 }, - { (char*) "Antarctica/Davis" , 0x021526 }, - { (char*) "Antarctica/DumontDUrville" , 0x0215FC }, - { (char*) "Antarctica/Macquarie" , 0x0216B0 }, - { (char*) "Antarctica/Mawson" , 0x021A9C }, - { (char*) "Antarctica/McMurdo" , 0x021B46 }, - { (char*) "Antarctica/Palmer" , 0x021E78 }, - { (char*) "Antarctica/Rothera" , 0x022201 }, - { (char*) "Antarctica/South_Pole" , 0x022298 }, - { (char*) "Antarctica/Syowa" , 0x0226B7 }, - { (char*) "Antarctica/Troll" , 0x02274D }, - { (char*) "Antarctica/Vostok" , 0x0227FC }, - { (char*) "Arctic/Longyearbyen" , 0x0228B8 }, - { (char*) "Asia/Aden" , 0x022B85 }, - { (char*) "Asia/Almaty" , 0x022C16 }, - { (char*) "Asia/Amman" , 0x022E9E }, - { (char*) "Asia/Anadyr" , 0x02324A }, - { (char*) "Asia/Aqtau" , 0x023550 }, - { (char*) "Asia/Aqtobe" , 0x0237CF }, - { (char*) "Asia/Ashgabat" , 0x023A4F }, - { (char*) "Asia/Ashkhabad" , 0x023BD2 }, - { (char*) "Asia/Atyrau" , 0x023D55 }, - { (char*) "Asia/Baghdad" , 0x023FDE }, - { (char*) "Asia/Bahrain" , 0x024260 }, - { (char*) "Asia/Baku" , 0x024319 }, - { (char*) "Asia/Bangkok" , 0x02460D }, - { (char*) "Asia/Barnaul" , 0x0246B1 }, - { (char*) "Asia/Beirut" , 0x0249BC }, - { (char*) "Asia/Bishkek" , 0x024CA4 }, - { (char*) "Asia/Brunei" , 0x024F1A }, - { (char*) "Asia/Calcutta" , 0x024FC0 }, - { (char*) "Asia/Chita" , 0x0250A8 }, - { (char*) "Asia/Choibalsan" , 0x0253B6 }, - { (char*) "Asia/Chongqing" , 0x025614 }, - { (char*) "Asia/Chungking" , 0x0257A9 }, - { (char*) "Asia/Colombo" , 0x02593E }, - { (char*) "Asia/Dacca" , 0x025A41 }, - { (char*) "Asia/Damascus" , 0x025B34 }, - { (char*) "Asia/Dhaka" , 0x026012 }, - { (char*) "Asia/Dili" , 0x026105 }, - { (char*) "Asia/Dubai" , 0x0261BB }, - { (char*) "Asia/Dushanbe" , 0x02624C }, - { (char*) "Asia/Famagusta" , 0x0263C6 }, - { (char*) "Asia/Gaza" , 0x02678D }, - { (char*) "Asia/Harbin" , 0x027329 }, - { (char*) "Asia/Hebron" , 0x0274BE }, - { (char*) "Asia/Ho_Chi_Minh" , 0x02806B }, - { (char*) "Asia/Hong_Kong" , 0x028163 }, - { (char*) "Asia/Hovd" , 0x028476 }, - { (char*) "Asia/Irkutsk" , 0x0286EA }, - { (char*) "Asia/Istanbul" , 0x028A08 }, - { (char*) "Asia/Jakarta" , 0x028EC4 }, - { (char*) "Asia/Jayapura" , 0x028FD5 }, - { (char*) "Asia/Jerusalem" , 0x0290C2 }, - { (char*) "Asia/Kabul" , 0x029500 }, - { (char*) "Asia/Kamchatka" , 0x0295AB }, - { (char*) "Asia/Karachi" , 0x0298A0 }, - { (char*) "Asia/Kashgar" , 0x0299B6 }, - { (char*) "Asia/Kathmandu" , 0x029A47 }, - { (char*) "Asia/Katmandu" , 0x029AF4 }, - { (char*) "Asia/Khandyga" , 0x029BA1 }, - { (char*) "Asia/Kolkata" , 0x029ED2 }, - { (char*) "Asia/Krasnoyarsk" , 0x029FBA }, - { (char*) "Asia/Kuala_Lumpur" , 0x02A2C4 }, - { (char*) "Asia/Kuching" , 0x02A3E4 }, - { (char*) "Asia/Kuwait" , 0x02A53E }, - { (char*) "Asia/Macao" , 0x02A5CF }, - { (char*) "Asia/Macau" , 0x02A8F2 }, - { (char*) "Asia/Magadan" , 0x02AC15 }, - { (char*) "Asia/Makassar" , 0x02AF20 }, - { (char*) "Asia/Manila" , 0x02B033 }, - { (char*) "Asia/Muscat" , 0x02B151 }, - { (char*) "Asia/Nicosia" , 0x02B1E2 }, - { (char*) "Asia/Novokuznetsk" , 0x02B451 }, - { (char*) "Asia/Novosibirsk" , 0x02B744 }, - { (char*) "Asia/Omsk" , 0x02BA55 }, - { (char*) "Asia/Oral" , 0x02BD53 }, - { (char*) "Asia/Phnom_Penh" , 0x02BFDF }, - { (char*) "Asia/Pontianak" , 0x02C0B3 }, - { (char*) "Asia/Pyongyang" , 0x02C1CC }, - { (char*) "Asia/Qatar" , 0x02C28F }, - { (char*) "Asia/Qostanay" , 0x02C333 }, - { (char*) "Asia/Qyzylorda" , 0x02C5C9 }, - { (char*) "Asia/Rangoon" , 0x02C862 }, - { (char*) "Asia/Riyadh" , 0x02C929 }, - { (char*) "Asia/Saigon" , 0x02C9BA }, - { (char*) "Asia/Sakhalin" , 0x02CAB2 }, - { (char*) "Asia/Samarkand" , 0x02CDC9 }, - { (char*) "Asia/Seoul" , 0x02CF54 }, - { (char*) "Asia/Shanghai" , 0x02D0FF }, - { (char*) "Asia/Singapore" , 0x02D2A0 }, - { (char*) "Asia/Srednekolymsk" , 0x02D3AC }, - { (char*) "Asia/Taipei" , 0x02D6BC }, - { (char*) "Asia/Tashkent" , 0x02D8C7 }, - { (char*) "Asia/Tbilisi" , 0x02DA52 }, - { (char*) "Asia/Tehran" , 0x02DCD3 }, - { (char*) "Asia/Tel_Aviv" , 0x02E00B }, - { (char*) "Asia/Thimbu" , 0x02E449 }, - { (char*) "Asia/Thimphu" , 0x02E4EF }, - { (char*) "Asia/Tokyo" , 0x02E595 }, - { (char*) "Asia/Tomsk" , 0x02E676 }, - { (char*) "Asia/Ujung_Pandang" , 0x02E981 }, - { (char*) "Asia/Ulaanbaatar" , 0x02EA4B }, - { (char*) "Asia/Ulan_Bator" , 0x02ECB9 }, - { (char*) "Asia/Urumqi" , 0x02EF17 }, - { (char*) "Asia/Ust-Nera" , 0x02EFB5 }, - { (char*) "Asia/Vientiane" , 0x02F2D8 }, - { (char*) "Asia/Vladivostok" , 0x02F3BE }, - { (char*) "Asia/Yakutsk" , 0x02F6C3 }, - { (char*) "Asia/Yangon" , 0x02F9C7 }, - { (char*) "Asia/Yekaterinburg" , 0x02FA8E }, - { (char*) "Asia/Yerevan" , 0x02FDA0 }, - { (char*) "Atlantic/Azores" , 0x030070 }, - { (char*) "Atlantic/Bermuda" , 0x0305FB }, - { (char*) "Atlantic/Canary" , 0x030A07 }, - { (char*) "Atlantic/Cape_Verde" , 0x030BFF }, - { (char*) "Atlantic/Faeroe" , 0x030CBA }, - { (char*) "Atlantic/Faroe" , 0x030E7F }, - { (char*) "Atlantic/Jan_Mayen" , 0x031044 }, - { (char*) "Atlantic/Madeira" , 0x031311 }, - { (char*) "Atlantic/Reykjavik" , 0x031888 }, - { (char*) "Atlantic/South_Georgia" , 0x031B85 }, - { (char*) "Atlantic/St_Helena" , 0x031C15 }, - { (char*) "Atlantic/Stanley" , 0x031CB6 }, - { (char*) "Australia/ACT" , 0x031FD7 }, - { (char*) "Australia/Adelaide" , 0x03236B }, - { (char*) "Australia/Brisbane" , 0x03271F }, - { (char*) "Australia/Broken_Hill" , 0x032863 }, - { (char*) "Australia/Canberra" , 0x032C38 }, - { (char*) "Australia/Currie" , 0x032FCC }, - { (char*) "Australia/Darwin" , 0x0333C3 }, - { (char*) "Australia/Eucla" , 0x0334CB }, - { (char*) "Australia/Hobart" , 0x03362A }, - { (char*) "Australia/LHI" , 0x033A29 }, - { (char*) "Australia/Lindeman" , 0x033CE9 }, - { (char*) "Australia/Lord_Howe" , 0x033E59 }, - { (char*) "Australia/Melbourne" , 0x034129 }, - { (char*) "Australia/North" , 0x0344C5 }, - { (char*) "Australia/NSW" , 0x0345BB }, - { (char*) "Australia/Perth" , 0x03494F }, - { (char*) "Australia/Queensland" , 0x034AAB }, - { (char*) "Australia/South" , 0x034BD8 }, - { (char*) "Australia/Sydney" , 0x034F7D }, - { (char*) "Australia/Tasmania" , 0x03532D }, - { (char*) "Australia/Victoria" , 0x035724 }, - { (char*) "Australia/West" , 0x035AB8 }, - { (char*) "Australia/Yancowinna" , 0x035BF6 }, - { (char*) "Brazil/Acre" , 0x035FAF }, - { (char*) "Brazil/DeNoronha" , 0x03615D }, - { (char*) "Brazil/East" , 0x03634D }, - { (char*) "Brazil/West" , 0x036711 }, - { (char*) "Canada/Atlantic" , 0x0368B9 }, - { (char*) "Canada/Central" , 0x036F4D }, - { (char*) "Canada/Eastern" , 0x037467 }, - { (char*) "Canada/Mountain" , 0x037B28 }, - { (char*) "Canada/Newfoundland" , 0x037EFE }, - { (char*) "Canada/Pacific" , 0x038660 }, - { (char*) "Canada/Saskatchewan" , 0x038B9E }, - { (char*) "Canada/Yukon" , 0x038E28 }, - { (char*) "CET" , 0x039239 }, - { (char*) "Chile/Continental" , 0x039694 }, - { (char*) "Chile/EasterIsland" , 0x039BEA }, - { (char*) "CST6CDT" , 0x03A08C }, - { (char*) "Cuba" , 0x03A772 }, - { (char*) "EET" , 0x03ABDB }, - { (char*) "Egypt" , 0x03AE91 }, - { (char*) "Eire" , 0x03B3BA }, - { (char*) "EST" , 0x03B99E }, - { (char*) "EST5EDT" , 0x03BA3F }, - { (char*) "Etc/GMT" , 0x03C11B }, - { (char*) "Etc/GMT+0" , 0x03C196 }, - { (char*) "Etc/GMT+1" , 0x03C211 }, - { (char*) "Etc/GMT+10" , 0x03C28E }, - { (char*) "Etc/GMT+11" , 0x03C30C }, - { (char*) "Etc/GMT+12" , 0x03C38A }, - { (char*) "Etc/GMT+2" , 0x03C408 }, - { (char*) "Etc/GMT+3" , 0x03C485 }, - { (char*) "Etc/GMT+4" , 0x03C502 }, - { (char*) "Etc/GMT+5" , 0x03C57F }, - { (char*) "Etc/GMT+6" , 0x03C5FC }, - { (char*) "Etc/GMT+7" , 0x03C679 }, - { (char*) "Etc/GMT+8" , 0x03C6F6 }, - { (char*) "Etc/GMT+9" , 0x03C773 }, - { (char*) "Etc/GMT-0" , 0x03C7F0 }, - { (char*) "Etc/GMT-1" , 0x03C86B }, - { (char*) "Etc/GMT-10" , 0x03C8E9 }, - { (char*) "Etc/GMT-11" , 0x03C968 }, - { (char*) "Etc/GMT-12" , 0x03C9E7 }, - { (char*) "Etc/GMT-13" , 0x03CA66 }, - { (char*) "Etc/GMT-14" , 0x03CAE5 }, - { (char*) "Etc/GMT-2" , 0x03CB64 }, - { (char*) "Etc/GMT-3" , 0x03CBE2 }, - { (char*) "Etc/GMT-4" , 0x03CC60 }, - { (char*) "Etc/GMT-5" , 0x03CCDE }, - { (char*) "Etc/GMT-6" , 0x03CD5C }, - { (char*) "Etc/GMT-7" , 0x03CDDA }, - { (char*) "Etc/GMT-8" , 0x03CE58 }, - { (char*) "Etc/GMT-9" , 0x03CED6 }, - { (char*) "Etc/GMT0" , 0x03CF54 }, - { (char*) "Etc/Greenwich" , 0x03CFCF }, - { (char*) "Etc/UCT" , 0x03D04A }, - { (char*) "Etc/Universal" , 0x03D0C5 }, - { (char*) "Etc/UTC" , 0x03D140 }, - { (char*) "Etc/Zulu" , 0x03D1BB }, - { (char*) "Europe/Amsterdam" , 0x03D236 }, - { (char*) "Europe/Andorra" , 0x03D671 }, - { (char*) "Europe/Astrakhan" , 0x03D802 }, - { (char*) "Europe/Athens" , 0x03DAF6 }, - { (char*) "Europe/Belfast" , 0x03DDAC }, - { (char*) "Europe/Belgrade" , 0x03E3F7 }, - { (char*) "Europe/Berlin" , 0x03E5E1 }, - { (char*) "Europe/Bratislava" , 0x03E8BD }, - { (char*) "Europe/Brussels" , 0x03EB9C }, - { (char*) "Europe/Bucharest" , 0x03EFF7 }, - { (char*) "Europe/Budapest" , 0x03F298 }, - { (char*) "Europe/Busingen" , 0x03F5A2 }, - { (char*) "Europe/Chisinau" , 0x03F7A7 }, - { (char*) "Europe/Copenhagen" , 0x03FAA6 }, - { (char*) "Europe/Dublin" , 0x03FD21 }, - { (char*) "Europe/Gibraltar" , 0x040305 }, - { (char*) "Europe/Guernsey" , 0x0407D5 }, - { (char*) "Europe/Helsinki" , 0x040E2C }, - { (char*) "Europe/Isle_of_Man" , 0x041019 }, - { (char*) "Europe/Istanbul" , 0x041664 }, - { (char*) "Europe/Jersey" , 0x041B20 }, - { (char*) "Europe/Kaliningrad" , 0x042177 }, - { (char*) "Europe/Kiev" , 0x04251F }, - { (char*) "Europe/Kirov" , 0x042759 }, - { (char*) "Europe/Kyiv" , 0x042A52 }, - { (char*) "Europe/Lisbon" , 0x042C9B }, - { (char*) "Europe/Ljubljana" , 0x043271 }, - { (char*) "Europe/London" , 0x04345B }, - { (char*) "Europe/Luxembourg" , 0x043AA6 }, - { (char*) "Europe/Madrid" , 0x043EF1 }, - { (char*) "Europe/Malta" , 0x04428E }, - { (char*) "Europe/Mariehamn" , 0x04463A }, - { (char*) "Europe/Minsk" , 0x044827 }, - { (char*) "Europe/Monaco" , 0x044B5B }, - { (char*) "Europe/Moscow" , 0x044FC1 }, - { (char*) "Europe/Nicosia" , 0x04536D }, - { (char*) "Europe/Oslo" , 0x0455CE }, - { (char*) "Europe/Paris" , 0x04587E }, - { (char*) "Europe/Podgorica" , 0x045CDB }, - { (char*) "Europe/Prague" , 0x045EC5 }, - { (char*) "Europe/Riga" , 0x0461A4 }, - { (char*) "Europe/Rome" , 0x046466 }, - { (char*) "Europe/Samara" , 0x046825 }, - { (char*) "Europe/San_Marino" , 0x046B26 }, - { (char*) "Europe/Sarajevo" , 0x046EE5 }, - { (char*) "Europe/Saratov" , 0x0470CF }, - { (char*) "Europe/Simferopol" , 0x0473C1 }, - { (char*) "Europe/Skopje" , 0x047734 }, - { (char*) "Europe/Sofia" , 0x04791E }, - { (char*) "Europe/Stockholm" , 0x047B7A }, - { (char*) "Europe/Tallinn" , 0x047D77 }, - { (char*) "Europe/Tirane" , 0x048026 }, - { (char*) "Europe/Tiraspol" , 0x04828E }, - { (char*) "Europe/Ulyanovsk" , 0x04858D }, - { (char*) "Europe/Uzhgorod" , 0x0488A3 }, - { (char*) "Europe/Vaduz" , 0x048ADD }, - { (char*) "Europe/Vatican" , 0x048CC7 }, - { (char*) "Europe/Vienna" , 0x049086 }, - { (char*) "Europe/Vilnius" , 0x049324 }, - { (char*) "Europe/Volgograd" , 0x0495D4 }, - { (char*) "Europe/Warsaw" , 0x0498E3 }, - { (char*) "Europe/Zagreb" , 0x049C8A }, - { (char*) "Europe/Zaporozhye" , 0x049E74 }, - { (char*) "Europe/Zurich" , 0x04A0AE }, - { (char*) "Factory" , 0x04A2AB }, - { (char*) "GB" , 0x04A328 }, - { (char*) "GB-Eire" , 0x04A973 }, - { (char*) "GMT" , 0x04AFBE }, - { (char*) "GMT+0" , 0x04B039 }, - { (char*) "GMT-0" , 0x04B0B4 }, - { (char*) "GMT0" , 0x04B12F }, - { (char*) "Greenwich" , 0x04B1AA }, - { (char*) "Hongkong" , 0x04B225 }, - { (char*) "HST" , 0x04B538 }, - { (char*) "Iceland" , 0x04B621 }, - { (char*) "Indian/Antananarivo" , 0x04B6AF }, - { (char*) "Indian/Chagos" , 0x04B75B }, - { (char*) "Indian/Christmas" , 0x04B7FF }, - { (char*) "Indian/Cocos" , 0x04B890 }, - { (char*) "Indian/Comoro" , 0x04B928 }, - { (char*) "Indian/Kerguelen" , 0x04B9B7 }, - { (char*) "Indian/Mahe" , 0x04BA48 }, - { (char*) "Indian/Maldives" , 0x04BAD9 }, - { (char*) "Indian/Mauritius" , 0x04BB7D }, - { (char*) "Indian/Mayotte" , 0x04BC3C }, - { (char*) "Indian/Reunion" , 0x04BCCB }, - { (char*) "Iran" , 0x04BD5C }, - { (char*) "Israel" , 0x04C094 }, - { (char*) "Jamaica" , 0x04C4D2 }, - { (char*) "Japan" , 0x04C631 }, - { (char*) "Kwajalein" , 0x04C712 }, - { (char*) "Libya" , 0x04C7F9 }, - { (char*) "MET" , 0x04C9B4 }, - { (char*) "Mexico/BajaNorte" , 0x04CE0F }, - { (char*) "Mexico/BajaSur" , 0x04D252 }, - { (char*) "Mexico/General" , 0x04D510 }, - { (char*) "MST" , 0x04D821 }, - { (char*) "MST7MDT" , 0x04D91D }, - { (char*) "Navajo" , 0x04DD3B }, - { (char*) "NZ" , 0x04E159 }, - { (char*) "NZ-CHAT" , 0x04E578 }, - { (char*) "Pacific/Apia" , 0x04E8AC }, - { (char*) "Pacific/Auckland" , 0x04EA4F }, - { (char*) "Pacific/Bougainville" , 0x04EE81 }, - { (char*) "Pacific/Chatham" , 0x04EF62 }, - { (char*) "Pacific/Chuuk" , 0x04F2A5 }, - { (char*) "Pacific/Easter" , 0x04F383 }, - { (char*) "Pacific/Efate" , 0x04F832 }, - { (char*) "Pacific/Enderbury" , 0x04F994 }, - { (char*) "Pacific/Fakaofo" , 0x04FA4C }, - { (char*) "Pacific/Fiji" , 0x04FAF1 }, - { (char*) "Pacific/Funafuti" , 0x04FC89 }, - { (char*) "Pacific/Galapagos" , 0x04FD1B }, - { (char*) "Pacific/Gambier" , 0x04FDE7 }, - { (char*) "Pacific/Guadalcanal" , 0x04FE86 }, - { (char*) "Pacific/Guam" , 0x04FF18 }, - { (char*) "Pacific/Honolulu" , 0x050082 }, - { (char*) "Pacific/Johnston" , 0x050171 }, - { (char*) "Pacific/Kanton" , 0x05025A }, - { (char*) "Pacific/Kiritimati" , 0x050321 }, - { (char*) "Pacific/Kosrae" , 0x0503E7 }, - { (char*) "Pacific/Kwajalein" , 0x0504EB }, - { (char*) "Pacific/Majuro" , 0x0505DB }, - { (char*) "Pacific/Marquesas" , 0x0506D9 }, - { (char*) "Pacific/Midway" , 0x050781 }, - { (char*) "Pacific/Nauru" , 0x050844 }, - { (char*) "Pacific/Niue" , 0x050907 }, - { (char*) "Pacific/Norfolk" , 0x0509AD }, - { (char*) "Pacific/Noumea" , 0x050AA6 }, - { (char*) "Pacific/Pago_Pago" , 0x050B78 }, - { (char*) "Pacific/Palau" , 0x050C16 }, - { (char*) "Pacific/Pitcairn" , 0x050CB6 }, - { (char*) "Pacific/Pohnpei" , 0x050D5B }, - { (char*) "Pacific/Ponape" , 0x050E4B }, - { (char*) "Pacific/Port_Moresby" , 0x050EDD }, - { (char*) "Pacific/Rarotonga" , 0x050F9B }, - { (char*) "Pacific/Saipan" , 0x05113D }, - { (char*) "Pacific/Samoa" , 0x05129E }, - { (char*) "Pacific/Tahiti" , 0x05133C }, - { (char*) "Pacific/Tarawa" , 0x0513DC }, - { (char*) "Pacific/Tongatapu" , 0x05147D }, - { (char*) "Pacific/Truk" , 0x051576 }, - { (char*) "Pacific/Wake" , 0x05161C }, - { (char*) "Pacific/Wallis" , 0x0516B9 }, - { (char*) "Pacific/Yap" , 0x05174B }, - { (char*) "Poland" , 0x0517F1 }, - { (char*) "Portugal" , 0x051B98 }, - { (char*) "PRC" , 0x05215B }, - { (char*) "PST8PDT" , 0x0522F0 }, - { (char*) "ROC" , 0x05280A }, - { (char*) "ROK" , 0x052A15 }, - { (char*) "Singapore" , 0x052BC0 }, - { (char*) "Turkey" , 0x052CCC }, - { (char*) "UCT" , 0x053188 }, - { (char*) "Universal" , 0x053203 }, - { (char*) "US/Alaska" , 0x05327E }, - { (char*) "US/Aleutian" , 0x05365B }, - { (char*) "US/Arizona" , 0x053A30 }, - { (char*) "US/Central" , 0x053B2C }, - { (char*) "US/East-Indiana" , 0x054212 }, - { (char*) "US/Eastern" , 0x054431 }, - { (char*) "US/Hawaii" , 0x054B0D }, - { (char*) "US/Indiana-Starke" , 0x054BF6 }, - { (char*) "US/Michigan" , 0x054FFA }, - { (char*) "US/Mountain" , 0x055389 }, - { (char*) "US/Pacific" , 0x0557A7 }, - { (char*) "US/Samoa" , 0x055CC1 }, - { (char*) "UTC" , 0x055D5F }, - { (char*) "W-SU" , 0x055DDA }, - { (char*) "WET" , 0x056172 }, - { (char*) "Zulu" , 0x056735 }, + { (char*) "America/Coyhaique" , 0x00B238 }, + { (char*) "America/Creston" , 0x00B7A2 }, + { (char*) "America/Cuiaba" , 0x00B85E }, + { (char*) "America/Curacao" , 0x00BC1B }, + { (char*) "America/Danmarkshavn" , 0x00BCBE }, + { (char*) "America/Dawson" , 0x00BEA3 }, + { (char*) "America/Dawson_Creek" , 0x00C2C6 }, + { (char*) "America/Denver" , 0x00C59D }, + { (char*) "America/Detroit" , 0x00C9D0 }, + { (char*) "America/Dominica" , 0x00CD78 }, + { (char*) "America/Edmonton" , 0x00CE06 }, + { (char*) "America/Eirunepe" , 0x00D1FE }, + { (char*) "America/El_Salvador" , 0x00D3CD }, + { (char*) "America/Ensenada" , 0x00D489 }, + { (char*) "America/Fort_Nelson" , 0x00D8CC }, + { (char*) "America/Fort_Wayne" , 0x00DE94 }, + { (char*) "America/Fortaleza" , 0x00E0B3 }, + { (char*) "America/Glace_Bay" , 0x00E2C9 }, + { (char*) "America/Godthab" , 0x00E660 }, + { (char*) "America/Goose_Bay" , 0x00EA31 }, + { (char*) "America/Grand_Turk" , 0x00F089 }, + { (char*) "America/Grenada" , 0x00F3EA }, + { (char*) "America/Guadeloupe" , 0x00F478 }, + { (char*) "America/Guatemala" , 0x00F506 }, + { (char*) "America/Guayaquil" , 0x00F5E6 }, + { (char*) "America/Guyana" , 0x00F6B7 }, + { (char*) "America/Halifax" , 0x00F778 }, + { (char*) "America/Havana" , 0x00FE2A }, + { (char*) "America/Hermosillo" , 0x010293 }, + { (char*) "America/Indiana/Indianapolis" , 0x0103A7 }, + { (char*) "America/Indiana/Knox" , 0x0105DF }, + { (char*) "America/Indiana/Marengo" , 0x0109F8 }, + { (char*) "America/Indiana/Petersburg" , 0x010C52 }, + { (char*) "America/Indiana/Tell_City" , 0x010F1C }, + { (char*) "America/Indiana/Vevay" , 0x011146 }, + { (char*) "America/Indiana/Vincennes" , 0x0112DD }, + { (char*) "America/Indiana/Winamac" , 0x011533 }, + { (char*) "America/Indianapolis" , 0x0117B0 }, + { (char*) "America/Inuvik" , 0x0119CF }, + { (char*) "America/Iqaluit" , 0x011D20 }, + { (char*) "America/Jamaica" , 0x01209C }, + { (char*) "America/Jujuy" , 0x0121FB }, + { (char*) "America/Juneau" , 0x0124B9 }, + { (char*) "America/Kentucky/Louisville" , 0x01289F }, + { (char*) "America/Kentucky/Monticello" , 0x012DA3 }, + { (char*) "America/Knox_IN" , 0x01318F }, + { (char*) "America/Kralendijk" , 0x013593 }, + { (char*) "America/La_Paz" , 0x013650 }, + { (char*) "America/Lima" , 0x013706 }, + { (char*) "America/Los_Angeles" , 0x01382D }, + { (char*) "America/Louisville" , 0x013D4E }, + { (char*) "America/Lower_Princes" , 0x014234 }, + { (char*) "America/Maceio" , 0x0142F1 }, + { (char*) "America/Managua" , 0x014503 }, + { (char*) "America/Manaus" , 0x014636 }, + { (char*) "America/Marigot" , 0x0147ED }, + { (char*) "America/Martinique" , 0x0148AA }, + { (char*) "America/Matamoros" , 0x014968 }, + { (char*) "America/Mazatlan" , 0x014B55 }, + { (char*) "America/Mendoza" , 0x014E45 }, + { (char*) "America/Menominee" , 0x015115 }, + { (char*) "America/Merida" , 0x0154D5 }, + { (char*) "America/Metlakatla" , 0x015780 }, + { (char*) "America/Mexico_City" , 0x0159ED }, + { (char*) "America/Miquelon" , 0x015D0C }, + { (char*) "America/Moncton" , 0x015F3E }, + { (char*) "America/Monterrey" , 0x016537 }, + { (char*) "America/Montevideo" , 0x01683E }, + { (char*) "America/Montreal" , 0x016C13 }, + { (char*) "America/Montserrat" , 0x0172D4 }, + { (char*) "America/Nassau" , 0x017362 }, + { (char*) "America/New_York" , 0x01775C }, + { (char*) "America/Nipigon" , 0x017E4C }, + { (char*) "America/Nome" , 0x01850D }, + { (char*) "America/Noronha" , 0x0188F5 }, + { (char*) "America/North_Dakota/Beulah" , 0x018AF5 }, + { (char*) "America/North_Dakota/Center" , 0x018F29 }, + { (char*) "America/North_Dakota/New_Salem" , 0x019328 }, + { (char*) "America/Nuuk" , 0x01972D }, + { (char*) "America/Ojinaga" , 0x019B0F }, + { (char*) "America/Panama" , 0x019E05 }, + { (char*) "America/Pangnirtung" , 0x019EA6 }, + { (char*) "America/Paramaribo" , 0x01A209 }, + { (char*) "America/Phoenix" , 0x01A2D0 }, + { (char*) "America/Port-au-Prince" , 0x01A3E4 }, + { (char*) "America/Port_of_Spain" , 0x01A625 }, + { (char*) "America/Porto_Acre" , 0x01A6B3 }, + { (char*) "America/Porto_Velho" , 0x01A861 }, + { (char*) "America/Puerto_Rico" , 0x01A9FF }, + { (char*) "America/Punta_Arenas" , 0x01AABC }, + { (char*) "America/Rainy_River" , 0x01AF9B }, + { (char*) "America/Rankin_Inlet" , 0x01B4B5 }, + { (char*) "America/Recife" , 0x01B7FE }, + { (char*) "America/Regina" , 0x01B9F8 }, + { (char*) "America/Resolute" , 0x01BC97 }, + { (char*) "America/Rio_Branco" , 0x01BFE1 }, + { (char*) "America/Rosario" , 0x01C193 }, + { (char*) "America/Santa_Isabel" , 0x01C463 }, + { (char*) "America/Santarem" , 0x01C8A6 }, + { (char*) "America/Santiago" , 0x01CA56 }, + { (char*) "America/Santo_Domingo" , 0x01CFB9 }, + { (char*) "America/Sao_Paulo" , 0x01D102 }, + { (char*) "America/Scoresbysund" , 0x01D4FC }, + { (char*) "America/Shiprock" , 0x01D8FD }, + { (char*) "America/Sitka" , 0x01DD1B }, + { (char*) "America/St_Barthelemy" , 0x01E0F6 }, + { (char*) "America/St_Johns" , 0x01E1B3 }, + { (char*) "America/St_Kitts" , 0x01E930 }, + { (char*) "America/St_Lucia" , 0x01E9BE }, + { (char*) "America/St_Thomas" , 0x01EA5F }, + { (char*) "America/St_Vincent" , 0x01EAED }, + { (char*) "America/Swift_Current" , 0x01EB8E }, + { (char*) "America/Tegucigalpa" , 0x01ED1C }, + { (char*) "America/Thule" , 0x01EDEA }, + { (char*) "America/Thunder_Bay" , 0x01EFCB }, + { (char*) "America/Tijuana" , 0x01F68C }, + { (char*) "America/Toronto" , 0x01FADE }, + { (char*) "America/Tortola" , 0x0201BD }, + { (char*) "America/Vancouver" , 0x02024B }, + { (char*) "America/Virgin" , 0x0207A2 }, + { (char*) "America/Whitehorse" , 0x02085F }, + { (char*) "America/Winnipeg" , 0x020C82 }, + { (char*) "America/Yakutat" , 0x0211B9 }, + { (char*) "America/Yellowknife" , 0x021587 }, + { (char*) "Antarctica/Casey" , 0x02195D }, + { (char*) "Antarctica/Davis" , 0x021A8D }, + { (char*) "Antarctica/DumontDUrville" , 0x021B63 }, + { (char*) "Antarctica/Macquarie" , 0x021C17 }, + { (char*) "Antarctica/Mawson" , 0x022003 }, + { (char*) "Antarctica/McMurdo" , 0x0220AD }, + { (char*) "Antarctica/Palmer" , 0x0223DF }, + { (char*) "Antarctica/Rothera" , 0x022768 }, + { (char*) "Antarctica/South_Pole" , 0x0227FF }, + { (char*) "Antarctica/Syowa" , 0x022C1E }, + { (char*) "Antarctica/Troll" , 0x022CB4 }, + { (char*) "Antarctica/Vostok" , 0x022D63 }, + { (char*) "Arctic/Longyearbyen" , 0x022E1F }, + { (char*) "Asia/Aden" , 0x0230EC }, + { (char*) "Asia/Almaty" , 0x02317D }, + { (char*) "Asia/Amman" , 0x023405 }, + { (char*) "Asia/Anadyr" , 0x0237B1 }, + { (char*) "Asia/Aqtau" , 0x023AB7 }, + { (char*) "Asia/Aqtobe" , 0x023D36 }, + { (char*) "Asia/Ashgabat" , 0x023FB6 }, + { (char*) "Asia/Ashkhabad" , 0x024139 }, + { (char*) "Asia/Atyrau" , 0x0242BC }, + { (char*) "Asia/Baghdad" , 0x024545 }, + { (char*) "Asia/Bahrain" , 0x0247C7 }, + { (char*) "Asia/Baku" , 0x024880 }, + { (char*) "Asia/Bangkok" , 0x024B74 }, + { (char*) "Asia/Barnaul" , 0x024C18 }, + { (char*) "Asia/Beirut" , 0x024F23 }, + { (char*) "Asia/Bishkek" , 0x02520B }, + { (char*) "Asia/Brunei" , 0x025481 }, + { (char*) "Asia/Calcutta" , 0x025527 }, + { (char*) "Asia/Chita" , 0x02560F }, + { (char*) "Asia/Choibalsan" , 0x02591D }, + { (char*) "Asia/Chongqing" , 0x025B7B }, + { (char*) "Asia/Chungking" , 0x025D10 }, + { (char*) "Asia/Colombo" , 0x025EA5 }, + { (char*) "Asia/Dacca" , 0x025FA8 }, + { (char*) "Asia/Damascus" , 0x02609B }, + { (char*) "Asia/Dhaka" , 0x026579 }, + { (char*) "Asia/Dili" , 0x02666C }, + { (char*) "Asia/Dubai" , 0x026722 }, + { (char*) "Asia/Dushanbe" , 0x0267B3 }, + { (char*) "Asia/Famagusta" , 0x02692D }, + { (char*) "Asia/Gaza" , 0x026CF4 }, + { (char*) "Asia/Harbin" , 0x027890 }, + { (char*) "Asia/Hebron" , 0x027A25 }, + { (char*) "Asia/Ho_Chi_Minh" , 0x0285D2 }, + { (char*) "Asia/Hong_Kong" , 0x0286CA }, + { (char*) "Asia/Hovd" , 0x0289DD }, + { (char*) "Asia/Irkutsk" , 0x028C51 }, + { (char*) "Asia/Istanbul" , 0x028F6F }, + { (char*) "Asia/Jakarta" , 0x02942B }, + { (char*) "Asia/Jayapura" , 0x02953C }, + { (char*) "Asia/Jerusalem" , 0x029629 }, + { (char*) "Asia/Kabul" , 0x029A67 }, + { (char*) "Asia/Kamchatka" , 0x029B12 }, + { (char*) "Asia/Karachi" , 0x029E07 }, + { (char*) "Asia/Kashgar" , 0x029F1D }, + { (char*) "Asia/Kathmandu" , 0x029FAE }, + { (char*) "Asia/Katmandu" , 0x02A05B }, + { (char*) "Asia/Khandyga" , 0x02A108 }, + { (char*) "Asia/Kolkata" , 0x02A439 }, + { (char*) "Asia/Krasnoyarsk" , 0x02A521 }, + { (char*) "Asia/Kuala_Lumpur" , 0x02A82B }, + { (char*) "Asia/Kuching" , 0x02A94B }, + { (char*) "Asia/Kuwait" , 0x02AAA5 }, + { (char*) "Asia/Macao" , 0x02AB36 }, + { (char*) "Asia/Macau" , 0x02AE59 }, + { (char*) "Asia/Magadan" , 0x02B17C }, + { (char*) "Asia/Makassar" , 0x02B487 }, + { (char*) "Asia/Manila" , 0x02B59A }, + { (char*) "Asia/Muscat" , 0x02B6B8 }, + { (char*) "Asia/Nicosia" , 0x02B749 }, + { (char*) "Asia/Novokuznetsk" , 0x02B9B8 }, + { (char*) "Asia/Novosibirsk" , 0x02BCAB }, + { (char*) "Asia/Omsk" , 0x02BFBC }, + { (char*) "Asia/Oral" , 0x02C2BA }, + { (char*) "Asia/Phnom_Penh" , 0x02C546 }, + { (char*) "Asia/Pontianak" , 0x02C61A }, + { (char*) "Asia/Pyongyang" , 0x02C733 }, + { (char*) "Asia/Qatar" , 0x02C7F6 }, + { (char*) "Asia/Qostanay" , 0x02C89A }, + { (char*) "Asia/Qyzylorda" , 0x02CB30 }, + { (char*) "Asia/Rangoon" , 0x02CDC9 }, + { (char*) "Asia/Riyadh" , 0x02CE90 }, + { (char*) "Asia/Saigon" , 0x02CF21 }, + { (char*) "Asia/Sakhalin" , 0x02D019 }, + { (char*) "Asia/Samarkand" , 0x02D330 }, + { (char*) "Asia/Seoul" , 0x02D4BB }, + { (char*) "Asia/Shanghai" , 0x02D666 }, + { (char*) "Asia/Singapore" , 0x02D807 }, + { (char*) "Asia/Srednekolymsk" , 0x02D913 }, + { (char*) "Asia/Taipei" , 0x02DC23 }, + { (char*) "Asia/Tashkent" , 0x02DE2E }, + { (char*) "Asia/Tbilisi" , 0x02DFB9 }, + { (char*) "Asia/Tehran" , 0x02E23A }, + { (char*) "Asia/Tel_Aviv" , 0x02E572 }, + { (char*) "Asia/Thimbu" , 0x02E9B0 }, + { (char*) "Asia/Thimphu" , 0x02EA56 }, + { (char*) "Asia/Tokyo" , 0x02EAFC }, + { (char*) "Asia/Tomsk" , 0x02EBDD }, + { (char*) "Asia/Ujung_Pandang" , 0x02EEE8 }, + { (char*) "Asia/Ulaanbaatar" , 0x02EFB2 }, + { (char*) "Asia/Ulan_Bator" , 0x02F220 }, + { (char*) "Asia/Urumqi" , 0x02F47E }, + { (char*) "Asia/Ust-Nera" , 0x02F51C }, + { (char*) "Asia/Vientiane" , 0x02F83F }, + { (char*) "Asia/Vladivostok" , 0x02F925 }, + { (char*) "Asia/Yakutsk" , 0x02FC2A }, + { (char*) "Asia/Yangon" , 0x02FF2E }, + { (char*) "Asia/Yekaterinburg" , 0x02FFF5 }, + { (char*) "Asia/Yerevan" , 0x030307 }, + { (char*) "Atlantic/Azores" , 0x0305D7 }, + { (char*) "Atlantic/Bermuda" , 0x030B62 }, + { (char*) "Atlantic/Canary" , 0x030F6E }, + { (char*) "Atlantic/Cape_Verde" , 0x031166 }, + { (char*) "Atlantic/Faeroe" , 0x031221 }, + { (char*) "Atlantic/Faroe" , 0x0313E6 }, + { (char*) "Atlantic/Jan_Mayen" , 0x0315AB }, + { (char*) "Atlantic/Madeira" , 0x031878 }, + { (char*) "Atlantic/Reykjavik" , 0x031DEF }, + { (char*) "Atlantic/South_Georgia" , 0x0320EC }, + { (char*) "Atlantic/St_Helena" , 0x03217C }, + { (char*) "Atlantic/Stanley" , 0x03221D }, + { (char*) "Australia/ACT" , 0x03253E }, + { (char*) "Australia/Adelaide" , 0x0328D2 }, + { (char*) "Australia/Brisbane" , 0x032C86 }, + { (char*) "Australia/Broken_Hill" , 0x032DCA }, + { (char*) "Australia/Canberra" , 0x03319F }, + { (char*) "Australia/Currie" , 0x033533 }, + { (char*) "Australia/Darwin" , 0x03392A }, + { (char*) "Australia/Eucla" , 0x033A32 }, + { (char*) "Australia/Hobart" , 0x033B91 }, + { (char*) "Australia/LHI" , 0x033F90 }, + { (char*) "Australia/Lindeman" , 0x034250 }, + { (char*) "Australia/Lord_Howe" , 0x0343C0 }, + { (char*) "Australia/Melbourne" , 0x034690 }, + { (char*) "Australia/North" , 0x034A2C }, + { (char*) "Australia/NSW" , 0x034B22 }, + { (char*) "Australia/Perth" , 0x034EB6 }, + { (char*) "Australia/Queensland" , 0x035012 }, + { (char*) "Australia/South" , 0x03513F }, + { (char*) "Australia/Sydney" , 0x0354E4 }, + { (char*) "Australia/Tasmania" , 0x035894 }, + { (char*) "Australia/Victoria" , 0x035C8B }, + { (char*) "Australia/West" , 0x03601F }, + { (char*) "Australia/Yancowinna" , 0x03615D }, + { (char*) "Brazil/Acre" , 0x036516 }, + { (char*) "Brazil/DeNoronha" , 0x0366C4 }, + { (char*) "Brazil/East" , 0x0368B4 }, + { (char*) "Brazil/West" , 0x036C78 }, + { (char*) "Canada/Atlantic" , 0x036E20 }, + { (char*) "Canada/Central" , 0x0374B4 }, + { (char*) "Canada/Eastern" , 0x0379CE }, + { (char*) "Canada/Mountain" , 0x03808F }, + { (char*) "Canada/Newfoundland" , 0x038465 }, + { (char*) "Canada/Pacific" , 0x038BC7 }, + { (char*) "Canada/Saskatchewan" , 0x039105 }, + { (char*) "Canada/Yukon" , 0x03938F }, + { (char*) "CET" , 0x0397A0 }, + { (char*) "Chile/Continental" , 0x039BFB }, + { (char*) "Chile/EasterIsland" , 0x03A151 }, + { (char*) "CST6CDT" , 0x03A5F3 }, + { (char*) "Cuba" , 0x03ACD9 }, + { (char*) "EET" , 0x03B142 }, + { (char*) "Egypt" , 0x03B3F8 }, + { (char*) "Eire" , 0x03B921 }, + { (char*) "EST" , 0x03BF05 }, + { (char*) "EST5EDT" , 0x03BFA6 }, + { (char*) "Etc/GMT" , 0x03C682 }, + { (char*) "Etc/GMT+0" , 0x03C6FD }, + { (char*) "Etc/GMT+1" , 0x03C778 }, + { (char*) "Etc/GMT+10" , 0x03C7F5 }, + { (char*) "Etc/GMT+11" , 0x03C873 }, + { (char*) "Etc/GMT+12" , 0x03C8F1 }, + { (char*) "Etc/GMT+2" , 0x03C96F }, + { (char*) "Etc/GMT+3" , 0x03C9EC }, + { (char*) "Etc/GMT+4" , 0x03CA69 }, + { (char*) "Etc/GMT+5" , 0x03CAE6 }, + { (char*) "Etc/GMT+6" , 0x03CB63 }, + { (char*) "Etc/GMT+7" , 0x03CBE0 }, + { (char*) "Etc/GMT+8" , 0x03CC5D }, + { (char*) "Etc/GMT+9" , 0x03CCDA }, + { (char*) "Etc/GMT-0" , 0x03CD57 }, + { (char*) "Etc/GMT-1" , 0x03CDD2 }, + { (char*) "Etc/GMT-10" , 0x03CE50 }, + { (char*) "Etc/GMT-11" , 0x03CECF }, + { (char*) "Etc/GMT-12" , 0x03CF4E }, + { (char*) "Etc/GMT-13" , 0x03CFCD }, + { (char*) "Etc/GMT-14" , 0x03D04C }, + { (char*) "Etc/GMT-2" , 0x03D0CB }, + { (char*) "Etc/GMT-3" , 0x03D149 }, + { (char*) "Etc/GMT-4" , 0x03D1C7 }, + { (char*) "Etc/GMT-5" , 0x03D245 }, + { (char*) "Etc/GMT-6" , 0x03D2C3 }, + { (char*) "Etc/GMT-7" , 0x03D341 }, + { (char*) "Etc/GMT-8" , 0x03D3BF }, + { (char*) "Etc/GMT-9" , 0x03D43D }, + { (char*) "Etc/GMT0" , 0x03D4BB }, + { (char*) "Etc/Greenwich" , 0x03D536 }, + { (char*) "Etc/UCT" , 0x03D5B1 }, + { (char*) "Etc/Universal" , 0x03D62C }, + { (char*) "Etc/UTC" , 0x03D6A7 }, + { (char*) "Etc/Zulu" , 0x03D722 }, + { (char*) "Europe/Amsterdam" , 0x03D79D }, + { (char*) "Europe/Andorra" , 0x03DBD8 }, + { (char*) "Europe/Astrakhan" , 0x03DD69 }, + { (char*) "Europe/Athens" , 0x03E05D }, + { (char*) "Europe/Belfast" , 0x03E313 }, + { (char*) "Europe/Belgrade" , 0x03E95E }, + { (char*) "Europe/Berlin" , 0x03EB48 }, + { (char*) "Europe/Bratislava" , 0x03EE24 }, + { (char*) "Europe/Brussels" , 0x03F103 }, + { (char*) "Europe/Bucharest" , 0x03F55E }, + { (char*) "Europe/Budapest" , 0x03F7FF }, + { (char*) "Europe/Busingen" , 0x03FB09 }, + { (char*) "Europe/Chisinau" , 0x03FD0E }, + { (char*) "Europe/Copenhagen" , 0x04000D }, + { (char*) "Europe/Dublin" , 0x040288 }, + { (char*) "Europe/Gibraltar" , 0x04086C }, + { (char*) "Europe/Guernsey" , 0x040D3C }, + { (char*) "Europe/Helsinki" , 0x041393 }, + { (char*) "Europe/Isle_of_Man" , 0x041580 }, + { (char*) "Europe/Istanbul" , 0x041BCB }, + { (char*) "Europe/Jersey" , 0x042087 }, + { (char*) "Europe/Kaliningrad" , 0x0426DE }, + { (char*) "Europe/Kiev" , 0x042A86 }, + { (char*) "Europe/Kirov" , 0x042CC0 }, + { (char*) "Europe/Kyiv" , 0x042FB9 }, + { (char*) "Europe/Lisbon" , 0x043202 }, + { (char*) "Europe/Ljubljana" , 0x0437D8 }, + { (char*) "Europe/London" , 0x0439C2 }, + { (char*) "Europe/Luxembourg" , 0x04400D }, + { (char*) "Europe/Madrid" , 0x044458 }, + { (char*) "Europe/Malta" , 0x0447F5 }, + { (char*) "Europe/Mariehamn" , 0x044BA1 }, + { (char*) "Europe/Minsk" , 0x044D8E }, + { (char*) "Europe/Monaco" , 0x0450C2 }, + { (char*) "Europe/Moscow" , 0x045528 }, + { (char*) "Europe/Nicosia" , 0x0458D4 }, + { (char*) "Europe/Oslo" , 0x045B35 }, + { (char*) "Europe/Paris" , 0x045DE5 }, + { (char*) "Europe/Podgorica" , 0x046242 }, + { (char*) "Europe/Prague" , 0x04642C }, + { (char*) "Europe/Riga" , 0x04670B }, + { (char*) "Europe/Rome" , 0x0469CD }, + { (char*) "Europe/Samara" , 0x046D8C }, + { (char*) "Europe/San_Marino" , 0x04708D }, + { (char*) "Europe/Sarajevo" , 0x04744C }, + { (char*) "Europe/Saratov" , 0x047636 }, + { (char*) "Europe/Simferopol" , 0x047928 }, + { (char*) "Europe/Skopje" , 0x047C9B }, + { (char*) "Europe/Sofia" , 0x047E85 }, + { (char*) "Europe/Stockholm" , 0x0480E1 }, + { (char*) "Europe/Tallinn" , 0x0482DE }, + { (char*) "Europe/Tirane" , 0x04858D }, + { (char*) "Europe/Tiraspol" , 0x0487F5 }, + { (char*) "Europe/Ulyanovsk" , 0x048AF4 }, + { (char*) "Europe/Uzhgorod" , 0x048E0A }, + { (char*) "Europe/Vaduz" , 0x049044 }, + { (char*) "Europe/Vatican" , 0x04922E }, + { (char*) "Europe/Vienna" , 0x0495ED }, + { (char*) "Europe/Vilnius" , 0x04988B }, + { (char*) "Europe/Volgograd" , 0x049B3B }, + { (char*) "Europe/Warsaw" , 0x049E4A }, + { (char*) "Europe/Zagreb" , 0x04A1F1 }, + { (char*) "Europe/Zaporozhye" , 0x04A3DB }, + { (char*) "Europe/Zurich" , 0x04A615 }, + { (char*) "Factory" , 0x04A812 }, + { (char*) "GB" , 0x04A88F }, + { (char*) "GB-Eire" , 0x04AEDA }, + { (char*) "GMT" , 0x04B525 }, + { (char*) "GMT+0" , 0x04B5A0 }, + { (char*) "GMT-0" , 0x04B61B }, + { (char*) "GMT0" , 0x04B696 }, + { (char*) "Greenwich" , 0x04B711 }, + { (char*) "Hongkong" , 0x04B78C }, + { (char*) "HST" , 0x04BA9F }, + { (char*) "Iceland" , 0x04BB88 }, + { (char*) "Indian/Antananarivo" , 0x04BC16 }, + { (char*) "Indian/Chagos" , 0x04BCC2 }, + { (char*) "Indian/Christmas" , 0x04BD66 }, + { (char*) "Indian/Cocos" , 0x04BDF7 }, + { (char*) "Indian/Comoro" , 0x04BE8F }, + { (char*) "Indian/Kerguelen" , 0x04BF1E }, + { (char*) "Indian/Mahe" , 0x04BFAF }, + { (char*) "Indian/Maldives" , 0x04C040 }, + { (char*) "Indian/Mauritius" , 0x04C0E4 }, + { (char*) "Indian/Mayotte" , 0x04C1A3 }, + { (char*) "Indian/Reunion" , 0x04C232 }, + { (char*) "Iran" , 0x04C2C3 }, + { (char*) "Israel" , 0x04C5FB }, + { (char*) "Jamaica" , 0x04CA39 }, + { (char*) "Japan" , 0x04CB98 }, + { (char*) "Kwajalein" , 0x04CC79 }, + { (char*) "Libya" , 0x04CD60 }, + { (char*) "MET" , 0x04CF1B }, + { (char*) "Mexico/BajaNorte" , 0x04D376 }, + { (char*) "Mexico/BajaSur" , 0x04D7B9 }, + { (char*) "Mexico/General" , 0x04DA77 }, + { (char*) "MST" , 0x04DD88 }, + { (char*) "MST7MDT" , 0x04DE84 }, + { (char*) "Navajo" , 0x04E2A2 }, + { (char*) "NZ" , 0x04E6C0 }, + { (char*) "NZ-CHAT" , 0x04EADF }, + { (char*) "Pacific/Apia" , 0x04EE13 }, + { (char*) "Pacific/Auckland" , 0x04EFB6 }, + { (char*) "Pacific/Bougainville" , 0x04F3E8 }, + { (char*) "Pacific/Chatham" , 0x04F4C9 }, + { (char*) "Pacific/Chuuk" , 0x04F80C }, + { (char*) "Pacific/Easter" , 0x04F8EA }, + { (char*) "Pacific/Efate" , 0x04FD99 }, + { (char*) "Pacific/Enderbury" , 0x04FEFB }, + { (char*) "Pacific/Fakaofo" , 0x04FFB3 }, + { (char*) "Pacific/Fiji" , 0x050058 }, + { (char*) "Pacific/Funafuti" , 0x0501F0 }, + { (char*) "Pacific/Galapagos" , 0x050282 }, + { (char*) "Pacific/Gambier" , 0x05034E }, + { (char*) "Pacific/Guadalcanal" , 0x0503ED }, + { (char*) "Pacific/Guam" , 0x05047F }, + { (char*) "Pacific/Honolulu" , 0x0505E9 }, + { (char*) "Pacific/Johnston" , 0x0506D8 }, + { (char*) "Pacific/Kanton" , 0x0507C1 }, + { (char*) "Pacific/Kiritimati" , 0x050888 }, + { (char*) "Pacific/Kosrae" , 0x05094E }, + { (char*) "Pacific/Kwajalein" , 0x050A52 }, + { (char*) "Pacific/Majuro" , 0x050B42 }, + { (char*) "Pacific/Marquesas" , 0x050C40 }, + { (char*) "Pacific/Midway" , 0x050CE8 }, + { (char*) "Pacific/Nauru" , 0x050DAB }, + { (char*) "Pacific/Niue" , 0x050E6E }, + { (char*) "Pacific/Norfolk" , 0x050F14 }, + { (char*) "Pacific/Noumea" , 0x05100D }, + { (char*) "Pacific/Pago_Pago" , 0x0510DF }, + { (char*) "Pacific/Palau" , 0x05117D }, + { (char*) "Pacific/Pitcairn" , 0x05121D }, + { (char*) "Pacific/Pohnpei" , 0x0512C2 }, + { (char*) "Pacific/Ponape" , 0x0513B2 }, + { (char*) "Pacific/Port_Moresby" , 0x051444 }, + { (char*) "Pacific/Rarotonga" , 0x051502 }, + { (char*) "Pacific/Saipan" , 0x0516A4 }, + { (char*) "Pacific/Samoa" , 0x051805 }, + { (char*) "Pacific/Tahiti" , 0x0518A3 }, + { (char*) "Pacific/Tarawa" , 0x051943 }, + { (char*) "Pacific/Tongatapu" , 0x0519E4 }, + { (char*) "Pacific/Truk" , 0x051ADD }, + { (char*) "Pacific/Wake" , 0x051B83 }, + { (char*) "Pacific/Wallis" , 0x051C20 }, + { (char*) "Pacific/Yap" , 0x051CB2 }, + { (char*) "Poland" , 0x051D58 }, + { (char*) "Portugal" , 0x0520FF }, + { (char*) "PRC" , 0x0526C2 }, + { (char*) "PST8PDT" , 0x052857 }, + { (char*) "ROC" , 0x052D71 }, + { (char*) "ROK" , 0x052F7C }, + { (char*) "Singapore" , 0x053127 }, + { (char*) "Turkey" , 0x053233 }, + { (char*) "UCT" , 0x0536EF }, + { (char*) "Universal" , 0x05376A }, + { (char*) "US/Alaska" , 0x0537E5 }, + { (char*) "US/Aleutian" , 0x053BC2 }, + { (char*) "US/Arizona" , 0x053F97 }, + { (char*) "US/Central" , 0x054093 }, + { (char*) "US/East-Indiana" , 0x054779 }, + { (char*) "US/Eastern" , 0x054998 }, + { (char*) "US/Hawaii" , 0x055074 }, + { (char*) "US/Indiana-Starke" , 0x05515D }, + { (char*) "US/Michigan" , 0x055561 }, + { (char*) "US/Mountain" , 0x0558F0 }, + { (char*) "US/Pacific" , 0x055D0E }, + { (char*) "US/Samoa" , 0x056228 }, + { (char*) "UTC" , 0x0562C6 }, + { (char*) "W-SU" , 0x056341 }, + { (char*) "WET" , 0x0566D9 }, + { (char*) "Zulu" , 0x056C9C }, }; -const unsigned char timelib_timezone_db_data_builtin[354224] = { +const unsigned char timelib_timezone_db_data_builtin[355607] = { /* Africa/Abidjan */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -3709,6 +3710,95 @@ const unsigned char timelib_timezone_db_data_builtin[354224] = { 0x54, 0x00, 0x0A, 0x43, 0x53, 0x54, 0x36, 0x0A, 0x00, 0x98, 0x7C, 0x75, 0x00, 0x92, 0x5B, 0x72, 0x00, 0x00, 0x00, 0x00, +/* America/Coyhaique */ +0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0xFF, +0xFF, 0xFF, 0xFF, 0x69, 0x87, 0x1F, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x30, 0x47, 0x45, 0xFF, +0xFF, 0xFF, 0xFF, 0x9B, 0x5C, 0xE5, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0x7C, 0xE2, 0xC5, 0xFF, +0xFF, 0xFF, 0xFF, 0xA1, 0x00, 0x71, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xB0, 0x5E, 0x77, 0xC5, 0xFF, +0xFF, 0xFF, 0xFF, 0xB1, 0x77, 0x3D, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xB2, 0x41, 0x00, 0xD0, 0xFF, +0xFF, 0xFF, 0xFF, 0xB3, 0x58, 0x70, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xB4, 0x22, 0x34, 0x50, 0xFF, +0xFF, 0xFF, 0xFF, 0xB5, 0x39, 0xA4, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xB6, 0x03, 0x67, 0xD0, 0xFF, +0xFF, 0xFF, 0xFF, 0xB7, 0x1A, 0xD7, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0xE4, 0x9B, 0x50, 0xFF, +0xFF, 0xFF, 0xFF, 0xB8, 0xFD, 0x5C, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xB9, 0xC7, 0x20, 0x50, 0xFF, +0xFF, 0xFF, 0xFF, 0xCC, 0x1C, 0x6E, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0x6C, 0xE7, 0xD0, 0xFF, +0xFF, 0xFF, 0xFF, 0xD4, 0x17, 0xE3, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0x33, 0x55, 0xC0, 0xFF, +0xFF, 0xFF, 0xFF, 0xD5, 0x76, 0x92, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xD1, 0x3C, 0x40, 0xFF, +0xFF, 0xFF, 0xFF, 0xFE, 0x92, 0xFA, 0xB0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0xCD, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x00, 0x72, 0xDC, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x75, 0x50, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x02, 0x40, 0x49, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x55, 0x32, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x04, 0x20, 0x2B, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x3E, 0x4F, 0x40, 0x00, +0x00, 0x00, 0x00, 0x06, 0x00, 0x0D, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0B, 0xBC, 0x40, 0x00, +0x00, 0x00, 0x00, 0x07, 0xDF, 0xEF, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x08, 0xFE, 0x13, 0x40, 0x00, +0x00, 0x00, 0x00, 0x09, 0xBF, 0xD1, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xDD, 0xF5, 0x40, 0x00, +0x00, 0x00, 0x00, 0x0B, 0xA8, 0xEE, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xBD, 0xD7, 0x40, 0x00, +0x00, 0x00, 0x00, 0x0D, 0x88, 0xD0, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x9D, 0xB9, 0x40, 0x00, +0x00, 0x00, 0x00, 0x0F, 0x68, 0xB2, 0x30, 0x00, 0x00, 0x00, 0x00, 0x10, 0x86, 0xD5, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x11, 0x48, 0x94, 0x30, 0x00, 0x00, 0x00, 0x00, 0x12, 0x66, 0xB7, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x13, 0x28, 0x76, 0x30, 0x00, 0x00, 0x00, 0x00, 0x14, 0x46, 0x99, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x15, 0x11, 0x92, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x26, 0x7B, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x16, 0xF1, 0x74, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x5D, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x18, 0xD1, 0x56, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x19, 0xE6, 0x3F, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x1A, 0xB1, 0x38, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xCF, 0x5C, 0x40, 0x00, +0x00, 0x00, 0x00, 0x1C, 0x91, 0x1A, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xAF, 0x3E, 0x40, 0x00, +0x00, 0x00, 0x00, 0x1E, 0x70, 0xFC, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x8F, 0x20, 0x40, 0x00, +0x00, 0x00, 0x00, 0x20, 0x7F, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x21, 0x6F, 0x02, 0x40, 0x00, +0x00, 0x00, 0x00, 0x22, 0x39, 0xFB, 0x30, 0x00, 0x00, 0x00, 0x00, 0x23, 0x4E, 0xE4, 0x40, 0x00, +0x00, 0x00, 0x00, 0x24, 0x19, 0xDD, 0x30, 0x00, 0x00, 0x00, 0x00, 0x25, 0x38, 0x00, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x25, 0xF9, 0xBF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x26, 0xF2, 0xF8, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x27, 0xD9, 0xA1, 0x30, 0x00, 0x00, 0x00, 0x00, 0x28, 0xF7, 0xC4, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x29, 0xC2, 0xBD, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xD7, 0xA6, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x2B, 0xA2, 0x9F, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xB7, 0x88, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x2D, 0x82, 0x81, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x97, 0x6A, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x2F, 0x62, 0x63, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0x87, 0x40, 0x00, +0x00, 0x00, 0x00, 0x31, 0x42, 0x45, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x32, 0x60, 0x69, 0x40, 0x00, +0x00, 0x00, 0x00, 0x33, 0x3D, 0xD7, 0x30, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x4B, 0x40, 0x00, +0x00, 0x00, 0x00, 0x35, 0x0B, 0x44, 0x30, 0x00, 0x00, 0x00, 0x00, 0x36, 0x0D, 0xB8, 0x40, 0x00, +0x00, 0x00, 0x00, 0x37, 0x06, 0xD5, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x0F, 0x40, 0x00, +0x00, 0x00, 0x00, 0x38, 0xCB, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00, 0x39, 0xE9, 0x2B, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x3A, 0xAA, 0xEA, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xC9, 0x0D, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x3C, 0x8A, 0xCC, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3D, 0xA8, 0xEF, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x3E, 0x6A, 0xAE, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x88, 0xD1, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x40, 0x53, 0xCA, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x41, 0x68, 0xB3, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x42, 0x33, 0xAC, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x43, 0x48, 0x95, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x44, 0x13, 0x8E, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x45, 0x31, 0xB2, 0x40, 0x00, +0x00, 0x00, 0x00, 0x45, 0xF3, 0x70, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x47, 0x11, 0x94, 0x40, 0x00, +0x00, 0x00, 0x00, 0x47, 0xEF, 0x02, 0x30, 0x00, 0x00, 0x00, 0x00, 0x48, 0xF1, 0x76, 0x40, 0x00, +0x00, 0x00, 0x00, 0x49, 0xBC, 0x6F, 0x30, 0x00, 0x00, 0x00, 0x00, 0x4A, 0xD1, 0x58, 0x40, 0x00, +0x00, 0x00, 0x00, 0x4B, 0xB8, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xB1, 0x3A, 0x40, 0x00, +0x00, 0x00, 0x00, 0x4D, 0xC6, 0x07, 0x30, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x50, 0x82, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x4F, 0x9C, 0xAE, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x50, 0x42, 0xD9, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x51, 0x7C, 0x90, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x52, 0x2B, 0xF6, 0x40, 0x00, +0x00, 0x00, 0x00, 0x53, 0x5C, 0x72, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x54, 0x0B, 0xD8, 0x40, 0x00, +0x00, 0x00, 0x00, 0x57, 0x37, 0xE6, 0x30, 0x00, 0x00, 0x00, 0x00, 0x57, 0xAF, 0xEC, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x59, 0x17, 0xC8, 0x30, 0x00, 0x00, 0x00, 0x00, 0x59, 0x8F, 0xCE, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x5A, 0xF7, 0xAA, 0x30, 0x00, 0x00, 0x00, 0x00, 0x5B, 0x6F, 0xB0, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x5C, 0xA9, 0x67, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x74, 0x7C, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x5E, 0x89, 0x49, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x54, 0x5E, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x60, 0x69, 0x2B, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x61, 0x34, 0x40, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x62, 0x49, 0x0D, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x63, 0x1D, 0x5D, 0x40, 0x00, +0x00, 0x00, 0x00, 0x64, 0x28, 0xEF, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x64, 0xF4, 0x04, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x66, 0x12, 0x0C, 0x30, 0x00, 0x00, 0x00, 0x00, 0x66, 0xDD, 0x21, 0x40, 0x00, +0x00, 0x00, 0x00, 0x67, 0xDB, 0x84, 0xB0, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04, 0x02, 0x04, 0x02, +0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x03, 0x02, 0x03, 0x04, 0x02, 0x03, 0x05, 0x03, 0x05, 0x03, +0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, +0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, +0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, +0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, +0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, +0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, +0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x06, 0xFF, 0xFF, 0xBC, 0x70, +0x00, 0x00, 0xFF, 0xFF, 0xBD, 0xBB, 0x00, 0x04, 0xFF, 0xFF, 0xB9, 0xB0, 0x00, 0x08, 0xFF, 0xFF, +0xC7, 0xC0, 0x00, 0x0C, 0xFF, 0xFF, 0xC7, 0xC0, 0x01, 0x0C, 0xFF, 0xFF, 0xD5, 0xD0, 0x01, 0x10, +0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x10, 0x4C, 0x4D, 0x54, 0x00, 0x53, 0x4D, 0x54, 0x00, 0x2D, 0x30, +0x35, 0x00, 0x2D, 0x30, 0x34, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x0A, 0x3C, 0x2D, 0x30, 0x33, 0x3E, +0x33, 0x0A, 0x00, 0x43, 0xCC, 0xC5, 0x00, 0xA4, 0xB1, 0x75, 0x00, 0x00, 0x00, 0x0C, 0x41, 0x79, +0x73, 0x65, 0x6E, 0x20, 0x52, 0x65, 0x67, 0x69, 0x6F, 0x6E, + /* America/Creston */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -7899,9 +7989,8 @@ const unsigned char timelib_timezone_db_data_builtin[354224] = { 0xC7, 0xC0, 0x00, 0x0C, 0xFF, 0xFF, 0xC7, 0xC0, 0x01, 0x0C, 0xFF, 0xFF, 0xD5, 0xD0, 0x01, 0x10, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x10, 0x4C, 0x4D, 0x54, 0x00, 0x53, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x35, 0x00, 0x2D, 0x30, 0x34, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x0A, 0x3C, 0x2D, 0x30, 0x33, 0x3E, -0x33, 0x0A, 0x00, 0x38, 0x3A, 0x88, 0x00, 0xA6, 0x72, 0xAD, 0x00, 0x00, 0x00, 0x14, 0x52, 0x65, -0x67, 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x4D, 0x61, 0x67, 0x61, 0x6C, 0x6C, 0x61, 0x6E, -0x65, 0x73, +0x33, 0x0A, 0x00, 0x38, 0x3A, 0x88, 0x00, 0xA6, 0x72, 0xAD, 0x00, 0x00, 0x00, 0x11, 0x4D, 0x61, +0x67, 0x61, 0x6C, 0x6C, 0x61, 0x6E, 0x65, 0x73, 0x20, 0x52, 0x65, 0x67, 0x69, 0x6F, 0x6E, /* America/Rainy_River */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -13146,7 +13235,7 @@ const unsigned char timelib_timezone_db_data_builtin[354224] = { 0xFF, 0xFF, 0xFF, 0x9A, 0x6C, 0x7D, 0xC8, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x00, 0xCC, 0x48, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x94, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xAD, 0x13, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x79, 0x73, 0x40, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0xCA, 0xC0, 0x00, -0x00, 0x00, 0x00, 0x10, 0xED, 0x3A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x11, 0xAD, 0xBC, 0x48, 0x00, +0x00, 0x00, 0x00, 0x10, 0xA9, 0xFD, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x11, 0xAD, 0xBC, 0x48, 0x00, 0x00, 0x00, 0x00, 0x12, 0x45, 0x4A, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, 0xEC, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x14, 0x2D, 0x15, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x28, 0x20, 0x76, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x28, 0xDB, 0x9D, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x29, 0xCB, 0x9C, 0xC8, 0x00, @@ -21311,7 +21400,7 @@ const unsigned char timelib_timezone_db_data_builtin[354224] = { 0xFF, 0xFF, 0xFF, 0x9A, 0x6C, 0x7D, 0xC8, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x00, 0xCC, 0x48, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x94, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xAD, 0x13, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x79, 0x73, 0x40, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0xCA, 0xC0, 0x00, -0x00, 0x00, 0x00, 0x10, 0xED, 0x3A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x11, 0xAD, 0xBC, 0x48, 0x00, +0x00, 0x00, 0x00, 0x10, 0xA9, 0xFD, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x11, 0xAD, 0xBC, 0x48, 0x00, 0x00, 0x00, 0x00, 0x12, 0x45, 0x4A, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, 0xEC, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x14, 0x2D, 0x15, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x28, 0x20, 0x76, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x28, 0xDB, 0x9D, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x29, 0xCB, 0x9C, 0xC8, 0x00, @@ -24240,7 +24329,7 @@ const unsigned char timelib_timezone_db_data_builtin[354224] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #else -const timelib_tzdb_index_entry timezonedb_idx_builtin[597] = { +const timelib_tzdb_index_entry timezonedb_idx_builtin[598] = { { (char*) "Africa/Abidjan" , 0x000000 }, { (char*) "Africa/Accra" , 0x0000A0 }, { (char*) "Africa/Addis_Ababa" , 0x0004D0 }, @@ -24340,508 +24429,509 @@ const timelib_tzdb_index_entry timezonedb_idx_builtin[597] = { { (char*) "America/Coral_Harbour" , 0x0114AF }, { (char*) "America/Cordoba" , 0x011571 }, { (char*) "America/Costa_Rica" , 0x0119A3 }, - { (char*) "America/Creston" , 0x011AEB }, - { (char*) "America/Cuiaba" , 0x011BD9 }, - { (char*) "America/Curacao" , 0x01216A }, - { (char*) "America/Danmarkshavn" , 0x012230 }, - { (char*) "America/Dawson" , 0x012510 }, - { (char*) "America/Dawson_Creek" , 0x012B7C }, - { (char*) "America/Denver" , 0x012FC2 }, - { (char*) "America/Detroit" , 0x01397F }, - { (char*) "America/Dominica" , 0x01425A }, - { (char*) "America/Edmonton" , 0x0142FA }, - { (char*) "America/Eirunepe" , 0x014C44 }, - { (char*) "America/El_Salvador" , 0x014EE1 }, - { (char*) "America/Ensenada" , 0x014FCD }, - { (char*) "America/Fort_Nelson" , 0x015973 }, - { (char*) "America/Fort_Wayne" , 0x016253 }, - { (char*) "America/Fortaleza" , 0x0168F1 }, - { (char*) "America/Glace_Bay" , 0x016BE1 }, - { (char*) "America/Godthab" , 0x017498 }, - { (char*) "America/Goose_Bay" , 0x017C05 }, - { (char*) "America/Grand_Turk" , 0x0188BB }, - { (char*) "America/Grenada" , 0x018FF1 }, - { (char*) "America/Guadeloupe" , 0x019091 }, - { (char*) "America/Guatemala" , 0x019131 }, - { (char*) "America/Guayaquil" , 0x019255 }, - { (char*) "America/Guyana" , 0x01935B }, - { (char*) "America/Halifax" , 0x01945F }, - { (char*) "America/Havana" , 0x01A1E9 }, - { (char*) "America/Hermosillo" , 0x01AB65 }, - { (char*) "America/Indiana/Indianapolis" , 0x01ACFB }, - { (char*) "America/Indiana/Knox" , 0x01B3B2 }, - { (char*) "America/Indiana/Marengo" , 0x01BD5F }, - { (char*) "America/Indiana/Petersburg" , 0x01C44C }, - { (char*) "America/Indiana/Tell_City" , 0x01CBEB }, - { (char*) "America/Indiana/Vevay" , 0x01D2AF }, - { (char*) "America/Indiana/Vincennes" , 0x01D86B }, - { (char*) "America/Indiana/Winamac" , 0x01DF41 }, - { (char*) "America/Indianapolis" , 0x01E665 }, - { (char*) "America/Inuvik" , 0x01ED03 }, - { (char*) "America/Iqaluit" , 0x01F53D }, - { (char*) "America/Jamaica" , 0x01FDFC }, - { (char*) "America/Jujuy" , 0x01FFEA }, - { (char*) "America/Juneau" , 0x020400 }, - { (char*) "America/Kentucky/Louisville" , 0x020D51 }, - { (char*) "America/Kentucky/Monticello" , 0x02185F }, - { (char*) "America/Knox_IN" , 0x0221BF }, - { (char*) "America/Kralendijk" , 0x022B57 }, - { (char*) "America/La_Paz" , 0x022C59 }, - { (char*) "America/Lima" , 0x022D3F }, - { (char*) "America/Los_Angeles" , 0x022ED3 }, - { (char*) "America/Louisville" , 0x023A0A }, - { (char*) "America/Lower_Princes" , 0x0244FA }, - { (char*) "America/Maceio" , 0x0245FC }, - { (char*) "America/Managua" , 0x0248F2 }, - { (char*) "America/Manaus" , 0x024AAC }, - { (char*) "America/Marigot" , 0x024D15 }, - { (char*) "America/Martinique" , 0x024E17 }, - { (char*) "America/Matamoros" , 0x024F0B }, - { (char*) "America/Mazatlan" , 0x0254CD }, - { (char*) "America/Mendoza" , 0x02592F }, - { (char*) "America/Menominee" , 0x025D61 }, - { (char*) "America/Merida" , 0x02666E }, - { (char*) "America/Metlakatla" , 0x026A77 }, - { (char*) "America/Mexico_City" , 0x027029 }, - { (char*) "America/Miquelon" , 0x027509 }, - { (char*) "America/Moncton" , 0x027B89 }, - { (char*) "America/Monterrey" , 0x0287FF }, - { (char*) "America/Montevideo" , 0x028C9B }, - { (char*) "America/Montreal" , 0x02927F }, - { (char*) "America/Montserrat" , 0x02A031 }, - { (char*) "America/Nassau" , 0x02A0D1 }, - { (char*) "America/New_York" , 0x02AA31 }, - { (char*) "America/Nipigon" , 0x02B831 }, - { (char*) "America/Nome" , 0x02C5E3 }, - { (char*) "America/Noronha" , 0x02CF3B }, - { (char*) "America/North_Dakota/Beulah" , 0x02D215 }, - { (char*) "America/North_Dakota/Center" , 0x02DB92 }, - { (char*) "America/North_Dakota/New_Salem" , 0x02E50F }, - { (char*) "America/Nuuk" , 0x02EE92 }, - { (char*) "America/Ojinaga" , 0x02F610 }, - { (char*) "America/Panama" , 0x02FC2C }, - { (char*) "America/Pangnirtung" , 0x02FCEE }, - { (char*) "America/Paramaribo" , 0x030594 }, - { (char*) "America/Phoenix" , 0x030698 }, - { (char*) "America/Port-au-Prince" , 0x030824 }, - { (char*) "America/Port_of_Spain" , 0x030DCA }, - { (char*) "America/Porto_Acre" , 0x030E6A }, - { (char*) "America/Porto_Velho" , 0x0310DC }, - { (char*) "America/Puerto_Rico" , 0x031322 }, - { (char*) "America/Punta_Arenas" , 0x031424 }, - { (char*) "America/Rainy_River" , 0x031BB2 }, - { (char*) "America/Rankin_Inlet" , 0x0326F2 }, - { (char*) "America/Recife" , 0x032F26 }, - { (char*) "America/Regina" , 0x0331FA }, - { (char*) "America/Resolute" , 0x0335EF }, - { (char*) "America/Rio_Branco" , 0x033E24 }, - { (char*) "America/Rosario" , 0x03409A }, - { (char*) "America/Santa_Isabel" , 0x0344CC }, - { (char*) "America/Santarem" , 0x034E72 }, - { (char*) "America/Santiago" , 0x0350D5 }, - { (char*) "America/Santo_Domingo" , 0x035AC1 }, - { (char*) "America/Sao_Paulo" , 0x035C97 }, - { (char*) "America/Scoresbysund" , 0x03626F }, - { (char*) "America/Shiprock" , 0x036A27 }, - { (char*) "America/Sitka" , 0x0373CF }, - { (char*) "America/St_Barthelemy" , 0x037D07 }, - { (char*) "America/St_Johns" , 0x037E09 }, - { (char*) "America/St_Kitts" , 0x038C77 }, - { (char*) "America/St_Lucia" , 0x038D17 }, - { (char*) "America/St_Thomas" , 0x038DD9 }, - { (char*) "America/St_Vincent" , 0x038E79 }, - { (char*) "America/Swift_Current" , 0x038F3B }, - { (char*) "America/Tegucigalpa" , 0x039189 }, - { (char*) "America/Thule" , 0x039291 }, - { (char*) "America/Thunder_Bay" , 0x039889 }, - { (char*) "America/Tijuana" , 0x03A63B }, - { (char*) "America/Toronto" , 0x03AFF0 }, - { (char*) "America/Tortola" , 0x03BDC0 }, - { (char*) "America/Vancouver" , 0x03BE60 }, - { (char*) "America/Virgin" , 0x03C9D1 }, - { (char*) "America/Whitehorse" , 0x03CAD3 }, - { (char*) "America/Winnipeg" , 0x03D13F }, - { (char*) "America/Yakutat" , 0x03DC9C }, - { (char*) "America/Yellowknife" , 0x03E5B9 }, - { (char*) "Antarctica/Casey" , 0x03EEE1 }, - { (char*) "Antarctica/Davis" , 0x03F099 }, - { (char*) "Antarctica/DumontDUrville" , 0x03F1C5 }, - { (char*) "Antarctica/Macquarie" , 0x03F295 }, - { (char*) "Antarctica/Mawson" , 0x03FB85 }, - { (char*) "Antarctica/McMurdo" , 0x03FC50 }, - { (char*) "Antarctica/Palmer" , 0x04044B }, - { (char*) "Antarctica/Rothera" , 0x0409D9 }, - { (char*) "Antarctica/South_Pole" , 0x040A82 }, - { (char*) "Antarctica/Syowa" , 0x041413 }, - { (char*) "Antarctica/Troll" , 0x0414BB }, - { (char*) "Antarctica/Vostok" , 0x041948 }, - { (char*) "Arctic/Longyearbyen" , 0x041A2F }, - { (char*) "Asia/Aden" , 0x042335 }, - { (char*) "Asia/Almaty" , 0x0423D8 }, - { (char*) "Asia/Amman" , 0x0427CD }, - { (char*) "Asia/Anadyr" , 0x042D72 }, - { (char*) "Asia/Aqtau" , 0x043227 }, - { (char*) "Asia/Aqtobe" , 0x043611 }, - { (char*) "Asia/Ashgabat" , 0x043A0F }, - { (char*) "Asia/Ashkhabad" , 0x043C78 }, - { (char*) "Asia/Atyrau" , 0x043EE1 }, - { (char*) "Asia/Baghdad" , 0x0442D3 }, - { (char*) "Asia/Bahrain" , 0x0446A8 }, - { (char*) "Asia/Baku" , 0x044793 }, - { (char*) "Asia/Bangkok" , 0x044C5C }, - { (char*) "Asia/Barnaul" , 0x044D21 }, - { (char*) "Asia/Beirut" , 0x0451F2 }, - { (char*) "Asia/Bishkek" , 0x045A68 }, - { (char*) "Asia/Brunei" , 0x045E3D }, - { (char*) "Asia/Calcutta" , 0x045F06 }, - { (char*) "Asia/Chita" , 0x04602F }, - { (char*) "Asia/Choibalsan" , 0x046506 }, - { (char*) "Asia/Chongqing" , 0x04687F }, - { (char*) "Asia/Chungking" , 0x046ABC }, - { (char*) "Asia/Colombo" , 0x046CF9 }, - { (char*) "Asia/Dacca" , 0x046E6B }, - { (char*) "Asia/Damascus" , 0x046FBA }, - { (char*) "Asia/Dhaka" , 0x047717 }, - { (char*) "Asia/Dili" , 0x047866 }, - { (char*) "Asia/Dubai" , 0x047973 }, - { (char*) "Asia/Dushanbe" , 0x047A16 }, - { (char*) "Asia/Famagusta" , 0x047C63 }, - { (char*) "Asia/Gaza" , 0x04846A }, - { (char*) "Asia/Harbin" , 0x049384 }, - { (char*) "Asia/Hebron" , 0x0495C1 }, - { (char*) "Asia/Ho_Chi_Minh" , 0x04A4F6 }, - { (char*) "Asia/Hong_Kong" , 0x04A653 }, - { (char*) "Asia/Hovd" , 0x04AB30 }, - { (char*) "Asia/Irkutsk" , 0x04AEBF }, - { (char*) "Asia/Istanbul" , 0x04B3B2 }, - { (char*) "Asia/Jakarta" , 0x04BB4B }, - { (char*) "Asia/Jayapura" , 0x04BCE3 }, - { (char*) "Asia/Jerusalem" , 0x04BE02 }, - { (char*) "Asia/Kabul" , 0x04C762 }, - { (char*) "Asia/Kamchatka" , 0x04C830 }, - { (char*) "Asia/Karachi" , 0x04CCCE }, - { (char*) "Asia/Kashgar" , 0x04CE55 }, - { (char*) "Asia/Kathmandu" , 0x04CEF8 }, - { (char*) "Asia/Katmandu" , 0x04CFCA }, - { (char*) "Asia/Khandyga" , 0x04D09C }, - { (char*) "Asia/Kolkata" , 0x04D5AF }, - { (char*) "Asia/Krasnoyarsk" , 0x04D6D8 }, - { (char*) "Asia/Kuala_Lumpur" , 0x04DBA6 }, - { (char*) "Asia/Kuching" , 0x04DD57 }, - { (char*) "Asia/Kuwait" , 0x04DF46 }, - { (char*) "Asia/Macao" , 0x04DFE9 }, - { (char*) "Asia/Macau" , 0x04E4C0 }, - { (char*) "Asia/Magadan" , 0x04E997 }, - { (char*) "Asia/Makassar" , 0x04EE6B }, - { (char*) "Asia/Manila" , 0x04EFBE }, - { (char*) "Asia/Muscat" , 0x04F170 }, - { (char*) "Asia/Nicosia" , 0x04F213 }, - { (char*) "Asia/Novokuznetsk" , 0x04F9FF }, - { (char*) "Asia/Novosibirsk" , 0x04FE9B }, - { (char*) "Asia/Omsk" , 0x050372 }, - { (char*) "Asia/Oral" , 0x050834 }, - { (char*) "Asia/Phnom_Penh" , 0x050C2E }, - { (char*) "Asia/Pontianak" , 0x050D53 }, - { (char*) "Asia/Pyongyang" , 0x050ED6 }, - { (char*) "Asia/Qatar" , 0x050FCF }, - { (char*) "Asia/Qostanay" , 0x051094 }, - { (char*) "Asia/Qyzylorda" , 0x0514BB }, - { (char*) "Asia/Rangoon" , 0x0518D7 }, - { (char*) "Asia/Riyadh" , 0x0519E1 }, - { (char*) "Asia/Saigon" , 0x051A84 }, - { (char*) "Asia/Sakhalin" , 0x051BE1 }, - { (char*) "Asia/Samarkand" , 0x0520A9 }, - { (char*) "Asia/Seoul" , 0x0522F9 }, - { (char*) "Asia/Shanghai" , 0x05256E }, - { (char*) "Asia/Singapore" , 0x0527B7 }, - { (char*) "Asia/Srednekolymsk" , 0x052954 }, - { (char*) "Asia/Taipei" , 0x052E28 }, - { (char*) "Asia/Tashkent" , 0x05312D }, - { (char*) "Asia/Tbilisi" , 0x05338B }, - { (char*) "Asia/Tehran" , 0x053794 }, - { (char*) "Asia/Tel_Aviv" , 0x053C80 }, - { (char*) "Asia/Thimbu" , 0x0545E0 }, - { (char*) "Asia/Thimphu" , 0x0546A9 }, - { (char*) "Asia/Tokyo" , 0x054772 }, - { (char*) "Asia/Tomsk" , 0x0548B3 }, - { (char*) "Asia/Ujung_Pandang" , 0x054D84 }, - { (char*) "Asia/Ulaanbaatar" , 0x054E8E }, - { (char*) "Asia/Ulan_Bator" , 0x055217 }, - { (char*) "Asia/Urumqi" , 0x055590 }, - { (char*) "Asia/Ust-Nera" , 0x055640 }, - { (char*) "Asia/Vientiane" , 0x055B36 }, - { (char*) "Asia/Vladivostok" , 0x055C77 }, - { (char*) "Asia/Yakutsk" , 0x056140 }, - { (char*) "Asia/Yangon" , 0x056608 }, - { (char*) "Asia/Yekaterinburg" , 0x056712 }, - { (char*) "Asia/Yerevan" , 0x056BF9 }, - { (char*) "Atlantic/Azores" , 0x057076 }, - { (char*) "Atlantic/Bermuda" , 0x057DFA }, - { (char*) "Atlantic/Canary" , 0x058762 }, - { (char*) "Atlantic/Cape_Verde" , 0x058EE5 }, - { (char*) "Atlantic/Faeroe" , 0x058FF1 }, - { (char*) "Atlantic/Faroe" , 0x059714 }, - { (char*) "Atlantic/Jan_Mayen" , 0x059E37 }, - { (char*) "Atlantic/Madeira" , 0x05A73D }, - { (char*) "Atlantic/Reykjavik" , 0x05B489 }, - { (char*) "Atlantic/South_Georgia" , 0x05B91F }, - { (char*) "Atlantic/St_Helena" , 0x05B9C1 }, - { (char*) "Atlantic/Stanley" , 0x05BA83 }, - { (char*) "Australia/ACT" , 0x05BF3F }, - { (char*) "Australia/Adelaide" , 0x05C7D9 }, - { (char*) "Australia/Brisbane" , 0x05D094 }, - { (char*) "Australia/Broken_Hill" , 0x05D25A }, - { (char*) "Australia/Canberra" , 0x05DB37 }, - { (char*) "Australia/Currie" , 0x05E3D1 }, - { (char*) "Australia/Darwin" , 0x05ED13 }, - { (char*) "Australia/Eucla" , 0x05EE76 }, - { (char*) "Australia/Hobart" , 0x05F063 }, - { (char*) "Australia/LHI" , 0x05F9AD }, - { (char*) "Australia/Lindeman" , 0x0600EF }, - { (char*) "Australia/Lord_Howe" , 0x0602F5 }, - { (char*) "Australia/Melbourne" , 0x060A47 }, - { (char*) "Australia/North" , 0x0612E9 }, - { (char*) "Australia/NSW" , 0x06143A }, - { (char*) "Australia/Perth" , 0x061CD4 }, - { (char*) "Australia/Queensland" , 0x061EBC }, - { (char*) "Australia/South" , 0x06206B }, - { (char*) "Australia/Sydney" , 0x062917 }, - { (char*) "Australia/Tasmania" , 0x0631CD }, - { (char*) "Australia/Victoria" , 0x063B0F }, - { (char*) "Australia/West" , 0x0643A9 }, - { (char*) "Australia/Yancowinna" , 0x064573 }, - { (char*) "Brazil/Acre" , 0x064E34 }, - { (char*) "Brazil/DeNoronha" , 0x0650A6 }, - { (char*) "Brazil/East" , 0x065370 }, - { (char*) "Brazil/West" , 0x065912 }, - { (char*) "Canada/Atlantic" , 0x065B6C }, - { (char*) "Canada/Central" , 0x0668D8 }, - { (char*) "Canada/Eastern" , 0x067418 }, - { (char*) "Canada/Mountain" , 0x0681CA }, - { (char*) "Canada/Newfoundland" , 0x068AF2 }, - { (char*) "Canada/Pacific" , 0x069945 }, - { (char*) "Canada/Saskatchewan" , 0x06A49D }, - { (char*) "Canada/Yukon" , 0x06A87D }, - { (char*) "CET" , 0x06AED7 }, - { (char*) "Chile/Continental" , 0x06BA58 }, - { (char*) "Chile/EasterIsland" , 0x06C437 }, - { (char*) "CST6CDT" , 0x06CCEE }, - { (char*) "Cuba" , 0x06DB02 }, - { (char*) "EET" , 0x06E47E }, - { (char*) "Egypt" , 0x06ED60 }, - { (char*) "Eire" , 0x06F6CB }, - { (char*) "EST" , 0x07047B }, - { (char*) "EST5EDT" , 0x07053D }, - { (char*) "Etc/GMT" , 0x071329 }, - { (char*) "Etc/GMT+0" , 0x0713A7 }, - { (char*) "Etc/GMT+1" , 0x071425 }, - { (char*) "Etc/GMT+10" , 0x0714A5 }, - { (char*) "Etc/GMT+11" , 0x071526 }, - { (char*) "Etc/GMT+12" , 0x0715A7 }, - { (char*) "Etc/GMT+2" , 0x071628 }, - { (char*) "Etc/GMT+3" , 0x0716A8 }, - { (char*) "Etc/GMT+4" , 0x071728 }, - { (char*) "Etc/GMT+5" , 0x0717A8 }, - { (char*) "Etc/GMT+6" , 0x071828 }, - { (char*) "Etc/GMT+7" , 0x0718A8 }, - { (char*) "Etc/GMT+8" , 0x071928 }, - { (char*) "Etc/GMT+9" , 0x0719A8 }, - { (char*) "Etc/GMT-0" , 0x071A28 }, - { (char*) "Etc/GMT-1" , 0x071AA6 }, - { (char*) "Etc/GMT-10" , 0x071B27 }, - { (char*) "Etc/GMT-11" , 0x071BA9 }, - { (char*) "Etc/GMT-12" , 0x071C2B }, - { (char*) "Etc/GMT-13" , 0x071CAD }, - { (char*) "Etc/GMT-14" , 0x071D2F }, - { (char*) "Etc/GMT-2" , 0x071DB1 }, - { (char*) "Etc/GMT-3" , 0x071E32 }, - { (char*) "Etc/GMT-4" , 0x071EB3 }, - { (char*) "Etc/GMT-5" , 0x071F34 }, - { (char*) "Etc/GMT-6" , 0x071FB5 }, - { (char*) "Etc/GMT-7" , 0x072036 }, - { (char*) "Etc/GMT-8" , 0x0720B7 }, - { (char*) "Etc/GMT-9" , 0x072138 }, - { (char*) "Etc/GMT0" , 0x0721B9 }, - { (char*) "Etc/Greenwich" , 0x072237 }, - { (char*) "Etc/UCT" , 0x0722B5 }, - { (char*) "Etc/Universal" , 0x072333 }, - { (char*) "Etc/UTC" , 0x0723B1 }, - { (char*) "Etc/Zulu" , 0x07242F }, - { (char*) "Europe/Amsterdam" , 0x0724AD }, - { (char*) "Europe/Andorra" , 0x073017 }, - { (char*) "Europe/Astrakhan" , 0x0736F1 }, - { (char*) "Europe/Athens" , 0x073B8E }, - { (char*) "Europe/Belfast" , 0x074470 }, - { (char*) "Europe/Belgrade" , 0x0752CC }, - { (char*) "Europe/Berlin" , 0x075A58 }, - { (char*) "Europe/Bratislava" , 0x07636D }, - { (char*) "Europe/Brussels" , 0x076C76 }, - { (char*) "Europe/Bucharest" , 0x0777F7 }, - { (char*) "Europe/Budapest" , 0x07808B }, - { (char*) "Europe/Busingen" , 0x0789D7 }, - { (char*) "Europe/Chisinau" , 0x079160 }, - { (char*) "Europe/Copenhagen" , 0x079AC2 }, - { (char*) "Europe/Dublin" , 0x07A327 }, - { (char*) "Europe/Gibraltar" , 0x07B0D7 }, - { (char*) "Europe/Guernsey" , 0x07BCDF }, - { (char*) "Europe/Helsinki" , 0x07CB7F }, - { (char*) "Europe/Isle_of_Man" , 0x07D2F7 }, - { (char*) "Europe/Istanbul" , 0x07E143 }, - { (char*) "Europe/Jersey" , 0x07E8DC }, - { (char*) "Europe/Kaliningrad" , 0x07F77C }, - { (char*) "Europe/Kiev" , 0x07FD71 }, - { (char*) "Europe/Kirov" , 0x0805C5 }, - { (char*) "Europe/Kyiv" , 0x080A80 }, - { (char*) "Europe/Lisbon" , 0x0812E3 }, - { (char*) "Europe/Ljubljana" , 0x0820C9 }, - { (char*) "Europe/London" , 0x082855 }, - { (char*) "Europe/Luxembourg" , 0x0836B1 }, - { (char*) "Europe/Madrid" , 0x08423F }, - { (char*) "Europe/Malta" , 0x084C91 }, - { (char*) "Europe/Mariehamn" , 0x0856D9 }, - { (char*) "Europe/Minsk" , 0x085E51 }, - { (char*) "Europe/Monaco" , 0x086378 }, - { (char*) "Europe/Moscow" , 0x086F04 }, - { (char*) "Europe/Nicosia" , 0x087523 }, - { (char*) "Europe/Oslo" , 0x087D01 }, - { (char*) "Europe/Paris" , 0x0885C1 }, - { (char*) "Europe/Podgorica" , 0x08915F }, - { (char*) "Europe/Prague" , 0x0898EB }, - { (char*) "Europe/Riga" , 0x08A1F4 }, - { (char*) "Europe/Rome" , 0x08AA96 }, - { (char*) "Europe/Samara" , 0x08B4F3 }, - { (char*) "Europe/San_Marino" , 0x08B9C9 }, - { (char*) "Europe/Sarajevo" , 0x08C426 }, - { (char*) "Europe/Saratov" , 0x08CBB2 }, - { (char*) "Europe/Simferopol" , 0x08D05F }, - { (char*) "Europe/Skopje" , 0x08D62E }, - { (char*) "Europe/Sofia" , 0x08DDBA }, - { (char*) "Europe/Stockholm" , 0x08E5E3 }, - { (char*) "Europe/Tallinn" , 0x08ED64 }, - { (char*) "Europe/Tirane" , 0x08F5D4 }, - { (char*) "Europe/Tiraspol" , 0x08FE04 }, - { (char*) "Europe/Ulyanovsk" , 0x090766 }, - { (char*) "Europe/Uzhgorod" , 0x090C69 }, - { (char*) "Europe/Vaduz" , 0x0914BD }, - { (char*) "Europe/Vatican" , 0x091C29 }, - { (char*) "Europe/Vienna" , 0x092686 }, - { (char*) "Europe/Vilnius" , 0x092F2A }, - { (char*) "Europe/Volgograd" , 0x0937A8 }, - { (char*) "Europe/Warsaw" , 0x093C6F }, - { (char*) "Europe/Zagreb" , 0x0946D9 }, - { (char*) "Europe/Zaporozhye" , 0x094E65 }, - { (char*) "Europe/Zurich" , 0x0956B9 }, - { (char*) "Factory" , 0x095E3A }, - { (char*) "GB" , 0x095EBA }, - { (char*) "GB-Eire" , 0x096D16 }, - { (char*) "GMT" , 0x097B72 }, - { (char*) "GMT+0" , 0x097BF0 }, - { (char*) "GMT-0" , 0x097C6E }, - { (char*) "GMT0" , 0x097CEC }, - { (char*) "Greenwich" , 0x097D6A }, - { (char*) "Hongkong" , 0x097DE8 }, - { (char*) "HST" , 0x0982C5 }, - { (char*) "Iceland" , 0x09841A }, - { (char*) "Indian/Antananarivo" , 0x0984BA }, - { (char*) "Indian/Chagos" , 0x0985A1 }, - { (char*) "Indian/Christmas" , 0x098666 }, - { (char*) "Indian/Cocos" , 0x098709 }, - { (char*) "Indian/Comoro" , 0x0987B5 }, - { (char*) "Indian/Kerguelen" , 0x098856 }, - { (char*) "Indian/Mahe" , 0x0988F9 }, - { (char*) "Indian/Maldives" , 0x09899C }, - { (char*) "Indian/Mauritius" , 0x098A61 }, - { (char*) "Indian/Mayotte" , 0x098B50 }, - { (char*) "Indian/Reunion" , 0x098BF1 }, - { (char*) "Iran" , 0x098C94 }, - { (char*) "Israel" , 0x099180 }, - { (char*) "Jamaica" , 0x099AE0 }, - { (char*) "Japan" , 0x099CCE }, - { (char*) "Kwajalein" , 0x099E0F }, - { (char*) "Libya" , 0x099F49 }, - { (char*) "MET" , 0x09A1C6 }, - { (char*) "Mexico/BajaNorte" , 0x09AD47 }, - { (char*) "Mexico/BajaSur" , 0x09B6ED }, - { (char*) "Mexico/General" , 0x09BB1D }, - { (char*) "MST" , 0x09BFEF }, - { (char*) "MST7MDT" , 0x09C163 }, - { (char*) "Navajo" , 0x09CB0B }, - { (char*) "NZ" , 0x09D4B3 }, - { (char*) "NZ-CHAT" , 0x09DE44 }, - { (char*) "Pacific/Apia" , 0x09E656 }, - { (char*) "Pacific/Auckland" , 0x09E8B8 }, - { (char*) "Pacific/Bougainville" , 0x09F25C }, - { (char*) "Pacific/Chatham" , 0x09F372 }, - { (char*) "Pacific/Chuuk" , 0x09FB93 }, - { (char*) "Pacific/Easter" , 0x09FCAD }, - { (char*) "Pacific/Efate" , 0x0A0571 }, - { (char*) "Pacific/Enderbury" , 0x0A0789 }, - { (char*) "Pacific/Fakaofo" , 0x0A0871 }, - { (char*) "Pacific/Fiji" , 0x0A0937 }, - { (char*) "Pacific/Funafuti" , 0x0A0B77 }, - { (char*) "Pacific/Galapagos" , 0x0A0C1B }, - { (char*) "Pacific/Gambier" , 0x0A0D18 }, - { (char*) "Pacific/Guadalcanal" , 0x0A0DC9 }, - { (char*) "Pacific/Guam" , 0x0A0E6D }, - { (char*) "Pacific/Honolulu" , 0x0A1067 }, - { (char*) "Pacific/Johnston" , 0x0A11C2 }, - { (char*) "Pacific/Kanton" , 0x0A1317 }, - { (char*) "Pacific/Kiritimati" , 0x0A140E }, - { (char*) "Pacific/Kosrae" , 0x0A1506 }, - { (char*) "Pacific/Kwajalein" , 0x0A1669 }, - { (char*) "Pacific/Majuro" , 0x0A17AC }, - { (char*) "Pacific/Marquesas" , 0x0A18F8 }, - { (char*) "Pacific/Midway" , 0x0A19B4 }, - { (char*) "Pacific/Nauru" , 0x0A1AA7 }, - { (char*) "Pacific/Niue" , 0x0A1BA1 }, - { (char*) "Pacific/Norfolk" , 0x0A1C6A }, - { (char*) "Pacific/Noumea" , 0x0A1FD8 }, - { (char*) "Pacific/Pago_Pago" , 0x0A2106 }, - { (char*) "Pacific/Palau" , 0x0A21C1 }, - { (char*) "Pacific/Pitcairn" , 0x0A2273 }, - { (char*) "Pacific/Pohnpei" , 0x0A233B }, - { (char*) "Pacific/Ponape" , 0x0A2476 }, - { (char*) "Pacific/Port_Moresby" , 0x0A251A }, - { (char*) "Pacific/Rarotonga" , 0x0A25EA }, - { (char*) "Pacific/Saipan" , 0x0A2843 }, - { (char*) "Pacific/Samoa" , 0x0A2A2F }, - { (char*) "Pacific/Tahiti" , 0x0A2AEA }, - { (char*) "Pacific/Tarawa" , 0x0A2B9C }, - { (char*) "Pacific/Tongatapu" , 0x0A2C4F }, - { (char*) "Pacific/Truk" , 0x0A2DC1 }, - { (char*) "Pacific/Wake" , 0x0A2E79 }, - { (char*) "Pacific/Wallis" , 0x0A2F28 }, - { (char*) "Pacific/Yap" , 0x0A2FCC }, - { (char*) "Poland" , 0x0A3084 }, - { (char*) "Portugal" , 0x0A3AEE }, - { (char*) "PRC" , 0x0A48C1 }, - { (char*) "PST8PDT" , 0x0A4AFE }, - { (char*) "ROC" , 0x0A562E }, - { (char*) "ROK" , 0x0A5933 }, - { (char*) "Singapore" , 0x0A5BA8 }, - { (char*) "Turkey" , 0x0A5D45 }, - { (char*) "UCT" , 0x0A64DE }, - { (char*) "Universal" , 0x0A655C }, - { (char*) "US/Alaska" , 0x0A65DA }, - { (char*) "US/Aleutian" , 0x0A6F29 }, - { (char*) "US/Arizona" , 0x0A7869 }, - { (char*) "US/Central" , 0x0A79DD }, - { (char*) "US/East-Indiana" , 0x0A87F1 }, - { (char*) "US/Eastern" , 0x0A8E8F }, - { (char*) "US/Hawaii" , 0x0A9C7B }, - { (char*) "US/Indiana-Starke" , 0x0A9DD0 }, - { (char*) "US/Michigan" , 0x0AA768 }, - { (char*) "US/Mountain" , 0x0AB02A }, - { (char*) "US/Pacific" , 0x0AB9D2 }, - { (char*) "US/Samoa" , 0x0AC502 }, - { (char*) "UTC" , 0x0AC5BD }, - { (char*) "W-SU" , 0x0AC63B }, - { (char*) "WET" , 0x0ACC46 }, - { (char*) "Zulu" , 0x0ADA19 }, + { (char*) "America/Coyhaique" , 0x011AEB }, + { (char*) "America/Creston" , 0x012351 }, + { (char*) "America/Cuiaba" , 0x01243F }, + { (char*) "America/Curacao" , 0x0129D0 }, + { (char*) "America/Danmarkshavn" , 0x012A96 }, + { (char*) "America/Dawson" , 0x012D76 }, + { (char*) "America/Dawson_Creek" , 0x0133E2 }, + { (char*) "America/Denver" , 0x013828 }, + { (char*) "America/Detroit" , 0x0141E5 }, + { (char*) "America/Dominica" , 0x014AC0 }, + { (char*) "America/Edmonton" , 0x014B60 }, + { (char*) "America/Eirunepe" , 0x0154AA }, + { (char*) "America/El_Salvador" , 0x015747 }, + { (char*) "America/Ensenada" , 0x015833 }, + { (char*) "America/Fort_Nelson" , 0x0161D9 }, + { (char*) "America/Fort_Wayne" , 0x016AB9 }, + { (char*) "America/Fortaleza" , 0x017157 }, + { (char*) "America/Glace_Bay" , 0x017447 }, + { (char*) "America/Godthab" , 0x017CFE }, + { (char*) "America/Goose_Bay" , 0x01846B }, + { (char*) "America/Grand_Turk" , 0x019121 }, + { (char*) "America/Grenada" , 0x019857 }, + { (char*) "America/Guadeloupe" , 0x0198F7 }, + { (char*) "America/Guatemala" , 0x019997 }, + { (char*) "America/Guayaquil" , 0x019ABB }, + { (char*) "America/Guyana" , 0x019BC1 }, + { (char*) "America/Halifax" , 0x019CC5 }, + { (char*) "America/Havana" , 0x01AA4F }, + { (char*) "America/Hermosillo" , 0x01B3CB }, + { (char*) "America/Indiana/Indianapolis" , 0x01B561 }, + { (char*) "America/Indiana/Knox" , 0x01BC18 }, + { (char*) "America/Indiana/Marengo" , 0x01C5C5 }, + { (char*) "America/Indiana/Petersburg" , 0x01CCB2 }, + { (char*) "America/Indiana/Tell_City" , 0x01D451 }, + { (char*) "America/Indiana/Vevay" , 0x01DB15 }, + { (char*) "America/Indiana/Vincennes" , 0x01E0D1 }, + { (char*) "America/Indiana/Winamac" , 0x01E7A7 }, + { (char*) "America/Indianapolis" , 0x01EECB }, + { (char*) "America/Inuvik" , 0x01F569 }, + { (char*) "America/Iqaluit" , 0x01FDA3 }, + { (char*) "America/Jamaica" , 0x020662 }, + { (char*) "America/Jujuy" , 0x020850 }, + { (char*) "America/Juneau" , 0x020C66 }, + { (char*) "America/Kentucky/Louisville" , 0x0215B7 }, + { (char*) "America/Kentucky/Monticello" , 0x0220C5 }, + { (char*) "America/Knox_IN" , 0x022A25 }, + { (char*) "America/Kralendijk" , 0x0233BD }, + { (char*) "America/La_Paz" , 0x0234BF }, + { (char*) "America/Lima" , 0x0235A5 }, + { (char*) "America/Los_Angeles" , 0x023739 }, + { (char*) "America/Louisville" , 0x024270 }, + { (char*) "America/Lower_Princes" , 0x024D60 }, + { (char*) "America/Maceio" , 0x024E62 }, + { (char*) "America/Managua" , 0x025158 }, + { (char*) "America/Manaus" , 0x025312 }, + { (char*) "America/Marigot" , 0x02557B }, + { (char*) "America/Martinique" , 0x02567D }, + { (char*) "America/Matamoros" , 0x025771 }, + { (char*) "America/Mazatlan" , 0x025D33 }, + { (char*) "America/Mendoza" , 0x026195 }, + { (char*) "America/Menominee" , 0x0265C7 }, + { (char*) "America/Merida" , 0x026ED4 }, + { (char*) "America/Metlakatla" , 0x0272DD }, + { (char*) "America/Mexico_City" , 0x02788F }, + { (char*) "America/Miquelon" , 0x027D6F }, + { (char*) "America/Moncton" , 0x0283EF }, + { (char*) "America/Monterrey" , 0x029065 }, + { (char*) "America/Montevideo" , 0x029501 }, + { (char*) "America/Montreal" , 0x029AE5 }, + { (char*) "America/Montserrat" , 0x02A897 }, + { (char*) "America/Nassau" , 0x02A937 }, + { (char*) "America/New_York" , 0x02B297 }, + { (char*) "America/Nipigon" , 0x02C097 }, + { (char*) "America/Nome" , 0x02CE49 }, + { (char*) "America/Noronha" , 0x02D7A1 }, + { (char*) "America/North_Dakota/Beulah" , 0x02DA7B }, + { (char*) "America/North_Dakota/Center" , 0x02E3F8 }, + { (char*) "America/North_Dakota/New_Salem" , 0x02ED75 }, + { (char*) "America/Nuuk" , 0x02F6F8 }, + { (char*) "America/Ojinaga" , 0x02FE76 }, + { (char*) "America/Panama" , 0x030492 }, + { (char*) "America/Pangnirtung" , 0x030554 }, + { (char*) "America/Paramaribo" , 0x030DFA }, + { (char*) "America/Phoenix" , 0x030EFE }, + { (char*) "America/Port-au-Prince" , 0x03108A }, + { (char*) "America/Port_of_Spain" , 0x031630 }, + { (char*) "America/Porto_Acre" , 0x0316D0 }, + { (char*) "America/Porto_Velho" , 0x031942 }, + { (char*) "America/Puerto_Rico" , 0x031B88 }, + { (char*) "America/Punta_Arenas" , 0x031C8A }, + { (char*) "America/Rainy_River" , 0x032415 }, + { (char*) "America/Rankin_Inlet" , 0x032F55 }, + { (char*) "America/Recife" , 0x033789 }, + { (char*) "America/Regina" , 0x033A5D }, + { (char*) "America/Resolute" , 0x033E52 }, + { (char*) "America/Rio_Branco" , 0x034687 }, + { (char*) "America/Rosario" , 0x0348FD }, + { (char*) "America/Santa_Isabel" , 0x034D2F }, + { (char*) "America/Santarem" , 0x0356D5 }, + { (char*) "America/Santiago" , 0x035938 }, + { (char*) "America/Santo_Domingo" , 0x036324 }, + { (char*) "America/Sao_Paulo" , 0x0364FA }, + { (char*) "America/Scoresbysund" , 0x036AD2 }, + { (char*) "America/Shiprock" , 0x03728A }, + { (char*) "America/Sitka" , 0x037C32 }, + { (char*) "America/St_Barthelemy" , 0x03856A }, + { (char*) "America/St_Johns" , 0x03866C }, + { (char*) "America/St_Kitts" , 0x0394DA }, + { (char*) "America/St_Lucia" , 0x03957A }, + { (char*) "America/St_Thomas" , 0x03963C }, + { (char*) "America/St_Vincent" , 0x0396DC }, + { (char*) "America/Swift_Current" , 0x03979E }, + { (char*) "America/Tegucigalpa" , 0x0399EC }, + { (char*) "America/Thule" , 0x039AF4 }, + { (char*) "America/Thunder_Bay" , 0x03A0EC }, + { (char*) "America/Tijuana" , 0x03AE9E }, + { (char*) "America/Toronto" , 0x03B853 }, + { (char*) "America/Tortola" , 0x03C623 }, + { (char*) "America/Vancouver" , 0x03C6C3 }, + { (char*) "America/Virgin" , 0x03D234 }, + { (char*) "America/Whitehorse" , 0x03D336 }, + { (char*) "America/Winnipeg" , 0x03D9A2 }, + { (char*) "America/Yakutat" , 0x03E4FF }, + { (char*) "America/Yellowknife" , 0x03EE1C }, + { (char*) "Antarctica/Casey" , 0x03F744 }, + { (char*) "Antarctica/Davis" , 0x03F8FC }, + { (char*) "Antarctica/DumontDUrville" , 0x03FA28 }, + { (char*) "Antarctica/Macquarie" , 0x03FAF8 }, + { (char*) "Antarctica/Mawson" , 0x0403E8 }, + { (char*) "Antarctica/McMurdo" , 0x0404B3 }, + { (char*) "Antarctica/Palmer" , 0x040CAE }, + { (char*) "Antarctica/Rothera" , 0x04123C }, + { (char*) "Antarctica/South_Pole" , 0x0412E5 }, + { (char*) "Antarctica/Syowa" , 0x041C76 }, + { (char*) "Antarctica/Troll" , 0x041D1E }, + { (char*) "Antarctica/Vostok" , 0x0421AB }, + { (char*) "Arctic/Longyearbyen" , 0x042292 }, + { (char*) "Asia/Aden" , 0x042B98 }, + { (char*) "Asia/Almaty" , 0x042C3B }, + { (char*) "Asia/Amman" , 0x043030 }, + { (char*) "Asia/Anadyr" , 0x0435D5 }, + { (char*) "Asia/Aqtau" , 0x043A8A }, + { (char*) "Asia/Aqtobe" , 0x043E74 }, + { (char*) "Asia/Ashgabat" , 0x044272 }, + { (char*) "Asia/Ashkhabad" , 0x0444DB }, + { (char*) "Asia/Atyrau" , 0x044744 }, + { (char*) "Asia/Baghdad" , 0x044B36 }, + { (char*) "Asia/Bahrain" , 0x044F0B }, + { (char*) "Asia/Baku" , 0x044FF6 }, + { (char*) "Asia/Bangkok" , 0x0454BF }, + { (char*) "Asia/Barnaul" , 0x045584 }, + { (char*) "Asia/Beirut" , 0x045A55 }, + { (char*) "Asia/Bishkek" , 0x0462CB }, + { (char*) "Asia/Brunei" , 0x0466A0 }, + { (char*) "Asia/Calcutta" , 0x046769 }, + { (char*) "Asia/Chita" , 0x046892 }, + { (char*) "Asia/Choibalsan" , 0x046D69 }, + { (char*) "Asia/Chongqing" , 0x0470E2 }, + { (char*) "Asia/Chungking" , 0x04731F }, + { (char*) "Asia/Colombo" , 0x04755C }, + { (char*) "Asia/Dacca" , 0x0476CE }, + { (char*) "Asia/Damascus" , 0x04781D }, + { (char*) "Asia/Dhaka" , 0x047F7A }, + { (char*) "Asia/Dili" , 0x0480C9 }, + { (char*) "Asia/Dubai" , 0x0481D6 }, + { (char*) "Asia/Dushanbe" , 0x048279 }, + { (char*) "Asia/Famagusta" , 0x0484C6 }, + { (char*) "Asia/Gaza" , 0x048CCD }, + { (char*) "Asia/Harbin" , 0x049BE7 }, + { (char*) "Asia/Hebron" , 0x049E24 }, + { (char*) "Asia/Ho_Chi_Minh" , 0x04AD59 }, + { (char*) "Asia/Hong_Kong" , 0x04AEB6 }, + { (char*) "Asia/Hovd" , 0x04B393 }, + { (char*) "Asia/Irkutsk" , 0x04B722 }, + { (char*) "Asia/Istanbul" , 0x04BC15 }, + { (char*) "Asia/Jakarta" , 0x04C3AE }, + { (char*) "Asia/Jayapura" , 0x04C546 }, + { (char*) "Asia/Jerusalem" , 0x04C665 }, + { (char*) "Asia/Kabul" , 0x04CFC5 }, + { (char*) "Asia/Kamchatka" , 0x04D093 }, + { (char*) "Asia/Karachi" , 0x04D531 }, + { (char*) "Asia/Kashgar" , 0x04D6B8 }, + { (char*) "Asia/Kathmandu" , 0x04D75B }, + { (char*) "Asia/Katmandu" , 0x04D82D }, + { (char*) "Asia/Khandyga" , 0x04D8FF }, + { (char*) "Asia/Kolkata" , 0x04DE12 }, + { (char*) "Asia/Krasnoyarsk" , 0x04DF3B }, + { (char*) "Asia/Kuala_Lumpur" , 0x04E409 }, + { (char*) "Asia/Kuching" , 0x04E5BA }, + { (char*) "Asia/Kuwait" , 0x04E7A9 }, + { (char*) "Asia/Macao" , 0x04E84C }, + { (char*) "Asia/Macau" , 0x04ED23 }, + { (char*) "Asia/Magadan" , 0x04F1FA }, + { (char*) "Asia/Makassar" , 0x04F6CE }, + { (char*) "Asia/Manila" , 0x04F821 }, + { (char*) "Asia/Muscat" , 0x04F9D3 }, + { (char*) "Asia/Nicosia" , 0x04FA76 }, + { (char*) "Asia/Novokuznetsk" , 0x050262 }, + { (char*) "Asia/Novosibirsk" , 0x0506FE }, + { (char*) "Asia/Omsk" , 0x050BD5 }, + { (char*) "Asia/Oral" , 0x051097 }, + { (char*) "Asia/Phnom_Penh" , 0x051491 }, + { (char*) "Asia/Pontianak" , 0x0515B6 }, + { (char*) "Asia/Pyongyang" , 0x051739 }, + { (char*) "Asia/Qatar" , 0x051832 }, + { (char*) "Asia/Qostanay" , 0x0518F7 }, + { (char*) "Asia/Qyzylorda" , 0x051D1E }, + { (char*) "Asia/Rangoon" , 0x05213A }, + { (char*) "Asia/Riyadh" , 0x052244 }, + { (char*) "Asia/Saigon" , 0x0522E7 }, + { (char*) "Asia/Sakhalin" , 0x052444 }, + { (char*) "Asia/Samarkand" , 0x05290C }, + { (char*) "Asia/Seoul" , 0x052B5C }, + { (char*) "Asia/Shanghai" , 0x052DD1 }, + { (char*) "Asia/Singapore" , 0x05301A }, + { (char*) "Asia/Srednekolymsk" , 0x0531B7 }, + { (char*) "Asia/Taipei" , 0x05368B }, + { (char*) "Asia/Tashkent" , 0x053990 }, + { (char*) "Asia/Tbilisi" , 0x053BEE }, + { (char*) "Asia/Tehran" , 0x053FF7 }, + { (char*) "Asia/Tel_Aviv" , 0x0544E3 }, + { (char*) "Asia/Thimbu" , 0x054E43 }, + { (char*) "Asia/Thimphu" , 0x054F0C }, + { (char*) "Asia/Tokyo" , 0x054FD5 }, + { (char*) "Asia/Tomsk" , 0x055116 }, + { (char*) "Asia/Ujung_Pandang" , 0x0555E7 }, + { (char*) "Asia/Ulaanbaatar" , 0x0556F1 }, + { (char*) "Asia/Ulan_Bator" , 0x055A7A }, + { (char*) "Asia/Urumqi" , 0x055DF3 }, + { (char*) "Asia/Ust-Nera" , 0x055EA3 }, + { (char*) "Asia/Vientiane" , 0x056399 }, + { (char*) "Asia/Vladivostok" , 0x0564DA }, + { (char*) "Asia/Yakutsk" , 0x0569A3 }, + { (char*) "Asia/Yangon" , 0x056E6B }, + { (char*) "Asia/Yekaterinburg" , 0x056F75 }, + { (char*) "Asia/Yerevan" , 0x05745C }, + { (char*) "Atlantic/Azores" , 0x0578D9 }, + { (char*) "Atlantic/Bermuda" , 0x05865D }, + { (char*) "Atlantic/Canary" , 0x058FC5 }, + { (char*) "Atlantic/Cape_Verde" , 0x059748 }, + { (char*) "Atlantic/Faeroe" , 0x059854 }, + { (char*) "Atlantic/Faroe" , 0x059F77 }, + { (char*) "Atlantic/Jan_Mayen" , 0x05A69A }, + { (char*) "Atlantic/Madeira" , 0x05AFA0 }, + { (char*) "Atlantic/Reykjavik" , 0x05BCEC }, + { (char*) "Atlantic/South_Georgia" , 0x05C182 }, + { (char*) "Atlantic/St_Helena" , 0x05C224 }, + { (char*) "Atlantic/Stanley" , 0x05C2E6 }, + { (char*) "Australia/ACT" , 0x05C7A2 }, + { (char*) "Australia/Adelaide" , 0x05D03C }, + { (char*) "Australia/Brisbane" , 0x05D8F7 }, + { (char*) "Australia/Broken_Hill" , 0x05DABD }, + { (char*) "Australia/Canberra" , 0x05E39A }, + { (char*) "Australia/Currie" , 0x05EC34 }, + { (char*) "Australia/Darwin" , 0x05F576 }, + { (char*) "Australia/Eucla" , 0x05F6D9 }, + { (char*) "Australia/Hobart" , 0x05F8C6 }, + { (char*) "Australia/LHI" , 0x060210 }, + { (char*) "Australia/Lindeman" , 0x060952 }, + { (char*) "Australia/Lord_Howe" , 0x060B58 }, + { (char*) "Australia/Melbourne" , 0x0612AA }, + { (char*) "Australia/North" , 0x061B4C }, + { (char*) "Australia/NSW" , 0x061C9D }, + { (char*) "Australia/Perth" , 0x062537 }, + { (char*) "Australia/Queensland" , 0x06271F }, + { (char*) "Australia/South" , 0x0628CE }, + { (char*) "Australia/Sydney" , 0x06317A }, + { (char*) "Australia/Tasmania" , 0x063A30 }, + { (char*) "Australia/Victoria" , 0x064372 }, + { (char*) "Australia/West" , 0x064C0C }, + { (char*) "Australia/Yancowinna" , 0x064DD6 }, + { (char*) "Brazil/Acre" , 0x065697 }, + { (char*) "Brazil/DeNoronha" , 0x065909 }, + { (char*) "Brazil/East" , 0x065BD3 }, + { (char*) "Brazil/West" , 0x066175 }, + { (char*) "Canada/Atlantic" , 0x0663CF }, + { (char*) "Canada/Central" , 0x06713B }, + { (char*) "Canada/Eastern" , 0x067C7B }, + { (char*) "Canada/Mountain" , 0x068A2D }, + { (char*) "Canada/Newfoundland" , 0x069355 }, + { (char*) "Canada/Pacific" , 0x06A1A8 }, + { (char*) "Canada/Saskatchewan" , 0x06AD00 }, + { (char*) "Canada/Yukon" , 0x06B0E0 }, + { (char*) "CET" , 0x06B73A }, + { (char*) "Chile/Continental" , 0x06C2BB }, + { (char*) "Chile/EasterIsland" , 0x06CC9A }, + { (char*) "CST6CDT" , 0x06D551 }, + { (char*) "Cuba" , 0x06E365 }, + { (char*) "EET" , 0x06ECE1 }, + { (char*) "Egypt" , 0x06F5C3 }, + { (char*) "Eire" , 0x06FF2E }, + { (char*) "EST" , 0x070CDE }, + { (char*) "EST5EDT" , 0x070DA0 }, + { (char*) "Etc/GMT" , 0x071B8C }, + { (char*) "Etc/GMT+0" , 0x071C0A }, + { (char*) "Etc/GMT+1" , 0x071C88 }, + { (char*) "Etc/GMT+10" , 0x071D08 }, + { (char*) "Etc/GMT+11" , 0x071D89 }, + { (char*) "Etc/GMT+12" , 0x071E0A }, + { (char*) "Etc/GMT+2" , 0x071E8B }, + { (char*) "Etc/GMT+3" , 0x071F0B }, + { (char*) "Etc/GMT+4" , 0x071F8B }, + { (char*) "Etc/GMT+5" , 0x07200B }, + { (char*) "Etc/GMT+6" , 0x07208B }, + { (char*) "Etc/GMT+7" , 0x07210B }, + { (char*) "Etc/GMT+8" , 0x07218B }, + { (char*) "Etc/GMT+9" , 0x07220B }, + { (char*) "Etc/GMT-0" , 0x07228B }, + { (char*) "Etc/GMT-1" , 0x072309 }, + { (char*) "Etc/GMT-10" , 0x07238A }, + { (char*) "Etc/GMT-11" , 0x07240C }, + { (char*) "Etc/GMT-12" , 0x07248E }, + { (char*) "Etc/GMT-13" , 0x072510 }, + { (char*) "Etc/GMT-14" , 0x072592 }, + { (char*) "Etc/GMT-2" , 0x072614 }, + { (char*) "Etc/GMT-3" , 0x072695 }, + { (char*) "Etc/GMT-4" , 0x072716 }, + { (char*) "Etc/GMT-5" , 0x072797 }, + { (char*) "Etc/GMT-6" , 0x072818 }, + { (char*) "Etc/GMT-7" , 0x072899 }, + { (char*) "Etc/GMT-8" , 0x07291A }, + { (char*) "Etc/GMT-9" , 0x07299B }, + { (char*) "Etc/GMT0" , 0x072A1C }, + { (char*) "Etc/Greenwich" , 0x072A9A }, + { (char*) "Etc/UCT" , 0x072B18 }, + { (char*) "Etc/Universal" , 0x072B96 }, + { (char*) "Etc/UTC" , 0x072C14 }, + { (char*) "Etc/Zulu" , 0x072C92 }, + { (char*) "Europe/Amsterdam" , 0x072D10 }, + { (char*) "Europe/Andorra" , 0x07387A }, + { (char*) "Europe/Astrakhan" , 0x073F54 }, + { (char*) "Europe/Athens" , 0x0743F1 }, + { (char*) "Europe/Belfast" , 0x074CD3 }, + { (char*) "Europe/Belgrade" , 0x075B2F }, + { (char*) "Europe/Berlin" , 0x0762BB }, + { (char*) "Europe/Bratislava" , 0x076BD0 }, + { (char*) "Europe/Brussels" , 0x0774D9 }, + { (char*) "Europe/Bucharest" , 0x07805A }, + { (char*) "Europe/Budapest" , 0x0788EE }, + { (char*) "Europe/Busingen" , 0x07923A }, + { (char*) "Europe/Chisinau" , 0x0799C3 }, + { (char*) "Europe/Copenhagen" , 0x07A325 }, + { (char*) "Europe/Dublin" , 0x07AB8A }, + { (char*) "Europe/Gibraltar" , 0x07B93A }, + { (char*) "Europe/Guernsey" , 0x07C542 }, + { (char*) "Europe/Helsinki" , 0x07D3E2 }, + { (char*) "Europe/Isle_of_Man" , 0x07DB5A }, + { (char*) "Europe/Istanbul" , 0x07E9A6 }, + { (char*) "Europe/Jersey" , 0x07F13F }, + { (char*) "Europe/Kaliningrad" , 0x07FFDF }, + { (char*) "Europe/Kiev" , 0x0805D4 }, + { (char*) "Europe/Kirov" , 0x080E28 }, + { (char*) "Europe/Kyiv" , 0x0812E3 }, + { (char*) "Europe/Lisbon" , 0x081B46 }, + { (char*) "Europe/Ljubljana" , 0x08292C }, + { (char*) "Europe/London" , 0x0830B8 }, + { (char*) "Europe/Luxembourg" , 0x083F14 }, + { (char*) "Europe/Madrid" , 0x084AA2 }, + { (char*) "Europe/Malta" , 0x0854F4 }, + { (char*) "Europe/Mariehamn" , 0x085F3C }, + { (char*) "Europe/Minsk" , 0x0866B4 }, + { (char*) "Europe/Monaco" , 0x086BDB }, + { (char*) "Europe/Moscow" , 0x087767 }, + { (char*) "Europe/Nicosia" , 0x087D86 }, + { (char*) "Europe/Oslo" , 0x088564 }, + { (char*) "Europe/Paris" , 0x088E24 }, + { (char*) "Europe/Podgorica" , 0x0899C2 }, + { (char*) "Europe/Prague" , 0x08A14E }, + { (char*) "Europe/Riga" , 0x08AA57 }, + { (char*) "Europe/Rome" , 0x08B2F9 }, + { (char*) "Europe/Samara" , 0x08BD56 }, + { (char*) "Europe/San_Marino" , 0x08C22C }, + { (char*) "Europe/Sarajevo" , 0x08CC89 }, + { (char*) "Europe/Saratov" , 0x08D415 }, + { (char*) "Europe/Simferopol" , 0x08D8C2 }, + { (char*) "Europe/Skopje" , 0x08DE91 }, + { (char*) "Europe/Sofia" , 0x08E61D }, + { (char*) "Europe/Stockholm" , 0x08EE46 }, + { (char*) "Europe/Tallinn" , 0x08F5C7 }, + { (char*) "Europe/Tirane" , 0x08FE37 }, + { (char*) "Europe/Tiraspol" , 0x090667 }, + { (char*) "Europe/Ulyanovsk" , 0x090FC9 }, + { (char*) "Europe/Uzhgorod" , 0x0914CC }, + { (char*) "Europe/Vaduz" , 0x091D20 }, + { (char*) "Europe/Vatican" , 0x09248C }, + { (char*) "Europe/Vienna" , 0x092EE9 }, + { (char*) "Europe/Vilnius" , 0x09378D }, + { (char*) "Europe/Volgograd" , 0x09400B }, + { (char*) "Europe/Warsaw" , 0x0944D2 }, + { (char*) "Europe/Zagreb" , 0x094F3C }, + { (char*) "Europe/Zaporozhye" , 0x0956C8 }, + { (char*) "Europe/Zurich" , 0x095F1C }, + { (char*) "Factory" , 0x09669D }, + { (char*) "GB" , 0x09671D }, + { (char*) "GB-Eire" , 0x097579 }, + { (char*) "GMT" , 0x0983D5 }, + { (char*) "GMT+0" , 0x098453 }, + { (char*) "GMT-0" , 0x0984D1 }, + { (char*) "GMT0" , 0x09854F }, + { (char*) "Greenwich" , 0x0985CD }, + { (char*) "Hongkong" , 0x09864B }, + { (char*) "HST" , 0x098B28 }, + { (char*) "Iceland" , 0x098C7D }, + { (char*) "Indian/Antananarivo" , 0x098D1D }, + { (char*) "Indian/Chagos" , 0x098E04 }, + { (char*) "Indian/Christmas" , 0x098EC9 }, + { (char*) "Indian/Cocos" , 0x098F6C }, + { (char*) "Indian/Comoro" , 0x099018 }, + { (char*) "Indian/Kerguelen" , 0x0990B9 }, + { (char*) "Indian/Mahe" , 0x09915C }, + { (char*) "Indian/Maldives" , 0x0991FF }, + { (char*) "Indian/Mauritius" , 0x0992C4 }, + { (char*) "Indian/Mayotte" , 0x0993B3 }, + { (char*) "Indian/Reunion" , 0x099454 }, + { (char*) "Iran" , 0x0994F7 }, + { (char*) "Israel" , 0x0999E3 }, + { (char*) "Jamaica" , 0x09A343 }, + { (char*) "Japan" , 0x09A531 }, + { (char*) "Kwajalein" , 0x09A672 }, + { (char*) "Libya" , 0x09A7AC }, + { (char*) "MET" , 0x09AA29 }, + { (char*) "Mexico/BajaNorte" , 0x09B5AA }, + { (char*) "Mexico/BajaSur" , 0x09BF50 }, + { (char*) "Mexico/General" , 0x09C380 }, + { (char*) "MST" , 0x09C852 }, + { (char*) "MST7MDT" , 0x09C9C6 }, + { (char*) "Navajo" , 0x09D36E }, + { (char*) "NZ" , 0x09DD16 }, + { (char*) "NZ-CHAT" , 0x09E6A7 }, + { (char*) "Pacific/Apia" , 0x09EEB9 }, + { (char*) "Pacific/Auckland" , 0x09F11B }, + { (char*) "Pacific/Bougainville" , 0x09FABF }, + { (char*) "Pacific/Chatham" , 0x09FBD5 }, + { (char*) "Pacific/Chuuk" , 0x0A03F6 }, + { (char*) "Pacific/Easter" , 0x0A0510 }, + { (char*) "Pacific/Efate" , 0x0A0DD4 }, + { (char*) "Pacific/Enderbury" , 0x0A0FEC }, + { (char*) "Pacific/Fakaofo" , 0x0A10D4 }, + { (char*) "Pacific/Fiji" , 0x0A119A }, + { (char*) "Pacific/Funafuti" , 0x0A13DA }, + { (char*) "Pacific/Galapagos" , 0x0A147E }, + { (char*) "Pacific/Gambier" , 0x0A157B }, + { (char*) "Pacific/Guadalcanal" , 0x0A162C }, + { (char*) "Pacific/Guam" , 0x0A16D0 }, + { (char*) "Pacific/Honolulu" , 0x0A18CA }, + { (char*) "Pacific/Johnston" , 0x0A1A25 }, + { (char*) "Pacific/Kanton" , 0x0A1B7A }, + { (char*) "Pacific/Kiritimati" , 0x0A1C71 }, + { (char*) "Pacific/Kosrae" , 0x0A1D69 }, + { (char*) "Pacific/Kwajalein" , 0x0A1ECC }, + { (char*) "Pacific/Majuro" , 0x0A200F }, + { (char*) "Pacific/Marquesas" , 0x0A215B }, + { (char*) "Pacific/Midway" , 0x0A2217 }, + { (char*) "Pacific/Nauru" , 0x0A230A }, + { (char*) "Pacific/Niue" , 0x0A2404 }, + { (char*) "Pacific/Norfolk" , 0x0A24CD }, + { (char*) "Pacific/Noumea" , 0x0A283B }, + { (char*) "Pacific/Pago_Pago" , 0x0A2969 }, + { (char*) "Pacific/Palau" , 0x0A2A24 }, + { (char*) "Pacific/Pitcairn" , 0x0A2AD6 }, + { (char*) "Pacific/Pohnpei" , 0x0A2B9E }, + { (char*) "Pacific/Ponape" , 0x0A2CD9 }, + { (char*) "Pacific/Port_Moresby" , 0x0A2D7D }, + { (char*) "Pacific/Rarotonga" , 0x0A2E4D }, + { (char*) "Pacific/Saipan" , 0x0A30A6 }, + { (char*) "Pacific/Samoa" , 0x0A3292 }, + { (char*) "Pacific/Tahiti" , 0x0A334D }, + { (char*) "Pacific/Tarawa" , 0x0A33FF }, + { (char*) "Pacific/Tongatapu" , 0x0A34B2 }, + { (char*) "Pacific/Truk" , 0x0A3624 }, + { (char*) "Pacific/Wake" , 0x0A36DC }, + { (char*) "Pacific/Wallis" , 0x0A378B }, + { (char*) "Pacific/Yap" , 0x0A382F }, + { (char*) "Poland" , 0x0A38E7 }, + { (char*) "Portugal" , 0x0A4351 }, + { (char*) "PRC" , 0x0A5124 }, + { (char*) "PST8PDT" , 0x0A5361 }, + { (char*) "ROC" , 0x0A5E91 }, + { (char*) "ROK" , 0x0A6196 }, + { (char*) "Singapore" , 0x0A640B }, + { (char*) "Turkey" , 0x0A65A8 }, + { (char*) "UCT" , 0x0A6D41 }, + { (char*) "Universal" , 0x0A6DBF }, + { (char*) "US/Alaska" , 0x0A6E3D }, + { (char*) "US/Aleutian" , 0x0A778C }, + { (char*) "US/Arizona" , 0x0A80CC }, + { (char*) "US/Central" , 0x0A8240 }, + { (char*) "US/East-Indiana" , 0x0A9054 }, + { (char*) "US/Eastern" , 0x0A96F2 }, + { (char*) "US/Hawaii" , 0x0AA4DE }, + { (char*) "US/Indiana-Starke" , 0x0AA633 }, + { (char*) "US/Michigan" , 0x0AAFCB }, + { (char*) "US/Mountain" , 0x0AB88D }, + { (char*) "US/Pacific" , 0x0AC235 }, + { (char*) "US/Samoa" , 0x0ACD65 }, + { (char*) "UTC" , 0x0ACE20 }, + { (char*) "W-SU" , 0x0ACE9E }, + { (char*) "WET" , 0x0AD4A9 }, + { (char*) "Zulu" , 0x0AE27C }, }; -const unsigned char timelib_timezone_db_data_builtin[711319] = { +const unsigned char timelib_timezone_db_data_builtin[713466] = { /* Africa/Abidjan */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -29630,6 +29720,143 @@ const unsigned char timelib_timezone_db_data_builtin[711319] = { 0x54, 0x00, 0x43, 0x53, 0x54, 0x00, 0x0A, 0x43, 0x53, 0x54, 0x36, 0x0A, 0x00, 0x98, 0x7C, 0x75, 0x00, 0x92, 0x5B, 0x72, 0x00, 0x00, 0x00, 0x00, +/* America/Coyhaique */ +0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00, +0x8F, 0x30, 0x47, 0x45, 0x9B, 0x5C, 0xE5, 0x50, 0x9F, 0x7C, 0xE2, 0xC5, 0xA1, 0x00, 0x71, 0xC0, +0xB0, 0x5E, 0x77, 0xC5, 0xB1, 0x77, 0x3D, 0x40, 0xB2, 0x41, 0x00, 0xD0, 0xB3, 0x58, 0x70, 0xC0, +0xB4, 0x22, 0x34, 0x50, 0xB5, 0x39, 0xA4, 0x40, 0xB6, 0x03, 0x67, 0xD0, 0xB7, 0x1A, 0xD7, 0xC0, +0xB7, 0xE4, 0x9B, 0x50, 0xB8, 0xFD, 0x5C, 0xC0, 0xB9, 0xC7, 0x20, 0x50, 0xCC, 0x1C, 0x6E, 0x40, +0xCC, 0x6C, 0xE7, 0xD0, 0xD4, 0x17, 0xE3, 0x40, 0xD5, 0x33, 0x55, 0xC0, 0xD5, 0x76, 0x92, 0x40, +0xFD, 0xD1, 0x3C, 0x40, 0xFE, 0x92, 0xFA, 0xB0, 0xFF, 0xCC, 0xCD, 0xC0, 0x00, 0x72, 0xDC, 0xB0, +0x01, 0x75, 0x50, 0xC0, 0x02, 0x40, 0x49, 0xB0, 0x03, 0x55, 0x32, 0xC0, 0x04, 0x20, 0x2B, 0xB0, +0x05, 0x3E, 0x4F, 0x40, 0x06, 0x00, 0x0D, 0xB0, 0x07, 0x0B, 0xBC, 0x40, 0x07, 0xDF, 0xEF, 0xB0, +0x08, 0xFE, 0x13, 0x40, 0x09, 0xBF, 0xD1, 0xB0, 0x0A, 0xDD, 0xF5, 0x40, 0x0B, 0xA8, 0xEE, 0x30, +0x0C, 0xBD, 0xD7, 0x40, 0x0D, 0x88, 0xD0, 0x30, 0x0E, 0x9D, 0xB9, 0x40, 0x0F, 0x68, 0xB2, 0x30, +0x10, 0x86, 0xD5, 0xC0, 0x11, 0x48, 0x94, 0x30, 0x12, 0x66, 0xB7, 0xC0, 0x13, 0x28, 0x76, 0x30, +0x14, 0x46, 0x99, 0xC0, 0x15, 0x11, 0x92, 0xB0, 0x16, 0x26, 0x7B, 0xC0, 0x16, 0xF1, 0x74, 0xB0, +0x18, 0x06, 0x5D, 0xC0, 0x18, 0xD1, 0x56, 0xB0, 0x19, 0xE6, 0x3F, 0xC0, 0x1A, 0xB1, 0x38, 0xB0, +0x1B, 0xCF, 0x5C, 0x40, 0x1C, 0x91, 0x1A, 0xB0, 0x1D, 0xAF, 0x3E, 0x40, 0x1E, 0x70, 0xFC, 0xB0, +0x1F, 0x8F, 0x20, 0x40, 0x20, 0x7F, 0x03, 0x30, 0x21, 0x6F, 0x02, 0x40, 0x22, 0x39, 0xFB, 0x30, +0x23, 0x4E, 0xE4, 0x40, 0x24, 0x19, 0xDD, 0x30, 0x25, 0x38, 0x00, 0xC0, 0x25, 0xF9, 0xBF, 0x30, +0x26, 0xF2, 0xF8, 0xC0, 0x27, 0xD9, 0xA1, 0x30, 0x28, 0xF7, 0xC4, 0xC0, 0x29, 0xC2, 0xBD, 0xB0, +0x2A, 0xD7, 0xA6, 0xC0, 0x2B, 0xA2, 0x9F, 0xB0, 0x2C, 0xB7, 0x88, 0xC0, 0x2D, 0x82, 0x81, 0xB0, +0x2E, 0x97, 0x6A, 0xC0, 0x2F, 0x62, 0x63, 0xB0, 0x30, 0x80, 0x87, 0x40, 0x31, 0x42, 0x45, 0xB0, +0x32, 0x60, 0x69, 0x40, 0x33, 0x3D, 0xD7, 0x30, 0x34, 0x40, 0x4B, 0x40, 0x35, 0x0B, 0x44, 0x30, +0x36, 0x0D, 0xB8, 0x40, 0x37, 0x06, 0xD5, 0xB0, 0x38, 0x00, 0x0F, 0x40, 0x38, 0xCB, 0x08, 0x30, +0x39, 0xE9, 0x2B, 0xC0, 0x3A, 0xAA, 0xEA, 0x30, 0x3B, 0xC9, 0x0D, 0xC0, 0x3C, 0x8A, 0xCC, 0x30, +0x3D, 0xA8, 0xEF, 0xC0, 0x3E, 0x6A, 0xAE, 0x30, 0x3F, 0x88, 0xD1, 0xC0, 0x40, 0x53, 0xCA, 0xB0, +0x41, 0x68, 0xB3, 0xC0, 0x42, 0x33, 0xAC, 0xB0, 0x43, 0x48, 0x95, 0xC0, 0x44, 0x13, 0x8E, 0xB0, +0x45, 0x31, 0xB2, 0x40, 0x45, 0xF3, 0x70, 0xB0, 0x47, 0x11, 0x94, 0x40, 0x47, 0xEF, 0x02, 0x30, +0x48, 0xF1, 0x76, 0x40, 0x49, 0xBC, 0x6F, 0x30, 0x4A, 0xD1, 0x58, 0x40, 0x4B, 0xB8, 0x00, 0xB0, +0x4C, 0xB1, 0x3A, 0x40, 0x4D, 0xC6, 0x07, 0x30, 0x4E, 0x50, 0x82, 0xC0, 0x4F, 0x9C, 0xAE, 0xB0, +0x50, 0x42, 0xD9, 0xC0, 0x51, 0x7C, 0x90, 0xB0, 0x52, 0x2B, 0xF6, 0x40, 0x53, 0x5C, 0x72, 0xB0, +0x54, 0x0B, 0xD8, 0x40, 0x57, 0x37, 0xE6, 0x30, 0x57, 0xAF, 0xEC, 0xC0, 0x59, 0x17, 0xC8, 0x30, +0x59, 0x8F, 0xCE, 0xC0, 0x5A, 0xF7, 0xAA, 0x30, 0x5B, 0x6F, 0xB0, 0xC0, 0x5C, 0xA9, 0x67, 0xB0, +0x5D, 0x74, 0x7C, 0xC0, 0x5E, 0x89, 0x49, 0xB0, 0x5F, 0x54, 0x5E, 0xC0, 0x60, 0x69, 0x2B, 0xB0, +0x61, 0x34, 0x40, 0xC0, 0x62, 0x49, 0x0D, 0xB0, 0x63, 0x1D, 0x5D, 0x40, 0x64, 0x28, 0xEF, 0xB0, +0x64, 0xF4, 0x04, 0xC0, 0x66, 0x12, 0x0C, 0x30, 0x66, 0xDD, 0x21, 0x40, 0x67, 0xDB, 0x84, 0xB0, +0x01, 0x02, 0x01, 0x03, 0x01, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x03, +0x02, 0x03, 0x04, 0x02, 0x03, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x07, 0xFF, 0xFF, 0xBC, 0x70, 0x00, 0x00, 0xFF, 0xFF, 0xBD, 0xBB, 0x00, +0x04, 0xFF, 0xFF, 0xB9, 0xB0, 0x00, 0x08, 0xFF, 0xFF, 0xC7, 0xC0, 0x00, 0x0C, 0xFF, 0xFF, 0xC7, +0xC0, 0x01, 0x0C, 0xFF, 0xFF, 0xD5, 0xD0, 0x01, 0x10, 0xFF, 0xFF, 0xC7, 0xC0, 0x00, 0x0C, 0xFF, +0xFF, 0xD5, 0xD0, 0x00, 0x10, 0x4C, 0x4D, 0x54, 0x00, 0x53, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x35, +0x00, 0x2D, 0x30, 0x34, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, +0x08, 0x00, 0x00, 0x00, 0x14, 0xFF, 0xFF, 0xFF, 0xFF, 0x69, 0x87, 0x1F, 0x10, 0xFF, 0xFF, 0xFF, +0xFF, 0x8F, 0x30, 0x47, 0x45, 0xFF, 0xFF, 0xFF, 0xFF, 0x9B, 0x5C, 0xE5, 0x50, 0xFF, 0xFF, 0xFF, +0xFF, 0x9F, 0x7C, 0xE2, 0xC5, 0xFF, 0xFF, 0xFF, 0xFF, 0xA1, 0x00, 0x71, 0xC0, 0xFF, 0xFF, 0xFF, +0xFF, 0xB0, 0x5E, 0x77, 0xC5, 0xFF, 0xFF, 0xFF, 0xFF, 0xB1, 0x77, 0x3D, 0x40, 0xFF, 0xFF, 0xFF, +0xFF, 0xB2, 0x41, 0x00, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xB3, 0x58, 0x70, 0xC0, 0xFF, 0xFF, 0xFF, +0xFF, 0xB4, 0x22, 0x34, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xB5, 0x39, 0xA4, 0x40, 0xFF, 0xFF, 0xFF, +0xFF, 0xB6, 0x03, 0x67, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0x1A, 0xD7, 0xC0, 0xFF, 0xFF, 0xFF, +0xFF, 0xB7, 0xE4, 0x9B, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xB8, 0xFD, 0x5C, 0xC0, 0xFF, 0xFF, 0xFF, +0xFF, 0xB9, 0xC7, 0x20, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0x1C, 0x6E, 0x40, 0xFF, 0xFF, 0xFF, +0xFF, 0xCC, 0x6C, 0xE7, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD4, 0x17, 0xE3, 0x40, 0xFF, 0xFF, 0xFF, +0xFF, 0xD5, 0x33, 0x55, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0x76, 0x92, 0x40, 0xFF, 0xFF, 0xFF, +0xFF, 0xFD, 0xD1, 0x3C, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x92, 0xFA, 0xB0, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xCC, 0xCD, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0xDC, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x01, 0x75, 0x50, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x49, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x03, 0x55, 0x32, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x2B, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x05, 0x3E, 0x4F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0D, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x07, 0x0B, 0xBC, 0x40, 0x00, 0x00, 0x00, 0x00, 0x07, 0xDF, 0xEF, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x08, 0xFE, 0x13, 0x40, 0x00, 0x00, 0x00, 0x00, 0x09, 0xBF, 0xD1, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x0A, 0xDD, 0xF5, 0x40, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xA8, 0xEE, 0x30, 0x00, 0x00, 0x00, +0x00, 0x0C, 0xBD, 0xD7, 0x40, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x88, 0xD0, 0x30, 0x00, 0x00, 0x00, +0x00, 0x0E, 0x9D, 0xB9, 0x40, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x68, 0xB2, 0x30, 0x00, 0x00, 0x00, +0x00, 0x10, 0x86, 0xD5, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x11, 0x48, 0x94, 0x30, 0x00, 0x00, 0x00, +0x00, 0x12, 0x66, 0xB7, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x13, 0x28, 0x76, 0x30, 0x00, 0x00, 0x00, +0x00, 0x14, 0x46, 0x99, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0x92, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x16, 0x26, 0x7B, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x16, 0xF1, 0x74, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x18, 0x06, 0x5D, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x18, 0xD1, 0x56, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x19, 0xE6, 0x3F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xB1, 0x38, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x1B, 0xCF, 0x5C, 0x40, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x91, 0x1A, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x1D, 0xAF, 0x3E, 0x40, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x70, 0xFC, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x1F, 0x8F, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x20, 0x7F, 0x03, 0x30, 0x00, 0x00, 0x00, +0x00, 0x21, 0x6F, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x22, 0x39, 0xFB, 0x30, 0x00, 0x00, 0x00, +0x00, 0x23, 0x4E, 0xE4, 0x40, 0x00, 0x00, 0x00, 0x00, 0x24, 0x19, 0xDD, 0x30, 0x00, 0x00, 0x00, +0x00, 0x25, 0x38, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x25, 0xF9, 0xBF, 0x30, 0x00, 0x00, 0x00, +0x00, 0x26, 0xF2, 0xF8, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x27, 0xD9, 0xA1, 0x30, 0x00, 0x00, 0x00, +0x00, 0x28, 0xF7, 0xC4, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x29, 0xC2, 0xBD, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x2A, 0xD7, 0xA6, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xA2, 0x9F, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x2C, 0xB7, 0x88, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x82, 0x81, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x2E, 0x97, 0x6A, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x62, 0x63, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x30, 0x80, 0x87, 0x40, 0x00, 0x00, 0x00, 0x00, 0x31, 0x42, 0x45, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x32, 0x60, 0x69, 0x40, 0x00, 0x00, 0x00, 0x00, 0x33, 0x3D, 0xD7, 0x30, 0x00, 0x00, 0x00, +0x00, 0x34, 0x40, 0x4B, 0x40, 0x00, 0x00, 0x00, 0x00, 0x35, 0x0B, 0x44, 0x30, 0x00, 0x00, 0x00, +0x00, 0x36, 0x0D, 0xB8, 0x40, 0x00, 0x00, 0x00, 0x00, 0x37, 0x06, 0xD5, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x38, 0x00, 0x0F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x38, 0xCB, 0x08, 0x30, 0x00, 0x00, 0x00, +0x00, 0x39, 0xE9, 0x2B, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xAA, 0xEA, 0x30, 0x00, 0x00, 0x00, +0x00, 0x3B, 0xC9, 0x0D, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x8A, 0xCC, 0x30, 0x00, 0x00, 0x00, +0x00, 0x3D, 0xA8, 0xEF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x6A, 0xAE, 0x30, 0x00, 0x00, 0x00, +0x00, 0x3F, 0x88, 0xD1, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x53, 0xCA, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x41, 0x68, 0xB3, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x33, 0xAC, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x43, 0x48, 0x95, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x44, 0x13, 0x8E, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x45, 0x31, 0xB2, 0x40, 0x00, 0x00, 0x00, 0x00, 0x45, 0xF3, 0x70, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x47, 0x11, 0x94, 0x40, 0x00, 0x00, 0x00, 0x00, 0x47, 0xEF, 0x02, 0x30, 0x00, 0x00, 0x00, +0x00, 0x48, 0xF1, 0x76, 0x40, 0x00, 0x00, 0x00, 0x00, 0x49, 0xBC, 0x6F, 0x30, 0x00, 0x00, 0x00, +0x00, 0x4A, 0xD1, 0x58, 0x40, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xB8, 0x00, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x4C, 0xB1, 0x3A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x4D, 0xC6, 0x07, 0x30, 0x00, 0x00, 0x00, +0x00, 0x4E, 0x50, 0x82, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x9C, 0xAE, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x50, 0x42, 0xD9, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x51, 0x7C, 0x90, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x52, 0x2B, 0xF6, 0x40, 0x00, 0x00, 0x00, 0x00, 0x53, 0x5C, 0x72, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x54, 0x0B, 0xD8, 0x40, 0x00, 0x00, 0x00, 0x00, 0x57, 0x37, 0xE6, 0x30, 0x00, 0x00, 0x00, +0x00, 0x57, 0xAF, 0xEC, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x59, 0x17, 0xC8, 0x30, 0x00, 0x00, 0x00, +0x00, 0x59, 0x8F, 0xCE, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xF7, 0xAA, 0x30, 0x00, 0x00, 0x00, +0x00, 0x5B, 0x6F, 0xB0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x5C, 0xA9, 0x67, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x5D, 0x74, 0x7C, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x89, 0x49, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x5F, 0x54, 0x5E, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x60, 0x69, 0x2B, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x61, 0x34, 0x40, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x62, 0x49, 0x0D, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x63, 0x1D, 0x5D, 0x40, 0x00, 0x00, 0x00, 0x00, 0x64, 0x28, 0xEF, 0xB0, 0x00, 0x00, 0x00, +0x00, 0x64, 0xF4, 0x04, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x66, 0x12, 0x0C, 0x30, 0x00, 0x00, 0x00, +0x00, 0x66, 0xDD, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x67, 0xDB, 0x84, 0xB0, 0x01, 0x02, 0x01, +0x03, 0x01, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x03, 0x02, 0x03, 0x04, +0x02, 0x03, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, +0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, +0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, +0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, +0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, +0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, +0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, +0x05, 0x07, 0xFF, 0xFF, 0xBC, 0x70, 0x00, 0x00, 0xFF, 0xFF, 0xBD, 0xBB, 0x00, 0x04, 0xFF, 0xFF, +0xB9, 0xB0, 0x00, 0x08, 0xFF, 0xFF, 0xC7, 0xC0, 0x00, 0x0C, 0xFF, 0xFF, 0xC7, 0xC0, 0x01, 0x0C, +0xFF, 0xFF, 0xD5, 0xD0, 0x01, 0x10, 0xFF, 0xFF, 0xC7, 0xC0, 0x00, 0x0C, 0xFF, 0xFF, 0xD5, 0xD0, +0x00, 0x10, 0x4C, 0x4D, 0x54, 0x00, 0x53, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x35, 0x00, 0x2D, 0x30, +0x34, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x0A, 0x3C, 0x2D, 0x30, 0x33, 0x3E, 0x33, 0x0A, 0x00, 0x43, +0xCC, 0xC5, 0x00, 0xA4, 0xB1, 0x75, 0x00, 0x00, 0x00, 0x0C, 0x41, 0x79, 0x73, 0x65, 0x6E, 0x20, +0x52, 0x65, 0x67, 0x69, 0x6F, 0x6E, + /* America/Creston */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -38062,8 +38289,8 @@ const unsigned char timelib_timezone_db_data_builtin[711319] = { 0x00, 0x10, 0x4C, 0x4D, 0x54, 0x00, 0x53, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x35, 0x00, 0x2D, 0x30, 0x34, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x0A, 0x3C, 0x2D, 0x30, 0x33, 0x3E, 0x33, 0x0A, 0x00, 0x38, -0x3A, 0x88, 0x00, 0xA6, 0x72, 0xAD, 0x00, 0x00, 0x00, 0x14, 0x52, 0x65, 0x67, 0x69, 0x6F, 0x6E, -0x20, 0x6F, 0x66, 0x20, 0x4D, 0x61, 0x67, 0x61, 0x6C, 0x6C, 0x61, 0x6E, 0x65, 0x73, +0x3A, 0x88, 0x00, 0xA6, 0x72, 0xAD, 0x00, 0x00, 0x00, 0x11, 0x4D, 0x61, 0x67, 0x61, 0x6C, 0x6C, +0x61, 0x6E, 0x65, 0x73, 0x20, 0x52, 0x65, 0x67, 0x69, 0x6F, 0x6E, /* America/Rainy_River */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -47037,7 +47264,7 @@ const unsigned char timelib_timezone_db_data_builtin[711319] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1C, 0x9A, 0x6C, 0x7D, 0xC8, 0xBF, 0x00, 0xCC, 0x48, 0x0D, 0x94, 0x44, 0x38, 0x0E, 0xAD, 0x13, 0xB8, 0x0F, 0x79, 0x73, 0x40, -0x10, 0x28, 0xCA, 0xC0, 0x10, 0xED, 0x3A, 0x40, 0x11, 0xAD, 0xBC, 0x48, 0x12, 0x45, 0x4A, 0xB8, +0x10, 0x28, 0xCA, 0xC0, 0x10, 0xA9, 0xFD, 0xC0, 0x11, 0xAD, 0xBC, 0x48, 0x12, 0x45, 0x4A, 0xB8, 0x13, 0x37, 0xEC, 0xC8, 0x14, 0x2D, 0x15, 0xB8, 0x28, 0x20, 0x76, 0xC8, 0x28, 0xDB, 0x9D, 0xB8, 0x29, 0xCB, 0x9C, 0xC8, 0x2A, 0xBE, 0x22, 0xB8, 0x2B, 0xAC, 0xD0, 0x48, 0x2C, 0x9F, 0x56, 0x38, 0x2D, 0x8E, 0x03, 0xC8, 0x2E, 0x80, 0x89, 0xB8, 0x2F, 0x6F, 0x37, 0x48, 0x30, 0x61, 0xBD, 0x38, @@ -47068,7 +47295,7 @@ const unsigned char timelib_timezone_db_data_builtin[711319] = { 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0x9A, 0x6C, 0x7D, 0xC8, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x00, 0xCC, 0x48, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x94, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xAD, 0x13, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x79, 0x73, 0x40, 0x00, -0x00, 0x00, 0x00, 0x10, 0x28, 0xCA, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x10, 0xED, 0x3A, 0x40, 0x00, +0x00, 0x00, 0x00, 0x10, 0x28, 0xCA, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA9, 0xFD, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x11, 0xAD, 0xBC, 0x48, 0x00, 0x00, 0x00, 0x00, 0x12, 0x45, 0x4A, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, 0xEC, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x14, 0x2D, 0x15, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x28, 0x20, 0x76, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x28, 0xDB, 0x9D, 0xB8, 0x00, @@ -65285,7 +65512,7 @@ const unsigned char timelib_timezone_db_data_builtin[711319] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1C, 0x9A, 0x6C, 0x7D, 0xC8, 0xBF, 0x00, 0xCC, 0x48, 0x0D, 0x94, 0x44, 0x38, 0x0E, 0xAD, 0x13, 0xB8, 0x0F, 0x79, 0x73, 0x40, -0x10, 0x28, 0xCA, 0xC0, 0x10, 0xED, 0x3A, 0x40, 0x11, 0xAD, 0xBC, 0x48, 0x12, 0x45, 0x4A, 0xB8, +0x10, 0x28, 0xCA, 0xC0, 0x10, 0xA9, 0xFD, 0xC0, 0x11, 0xAD, 0xBC, 0x48, 0x12, 0x45, 0x4A, 0xB8, 0x13, 0x37, 0xEC, 0xC8, 0x14, 0x2D, 0x15, 0xB8, 0x28, 0x20, 0x76, 0xC8, 0x28, 0xDB, 0x9D, 0xB8, 0x29, 0xCB, 0x9C, 0xC8, 0x2A, 0xBE, 0x22, 0xB8, 0x2B, 0xAC, 0xD0, 0x48, 0x2C, 0x9F, 0x56, 0x38, 0x2D, 0x8E, 0x03, 0xC8, 0x2E, 0x80, 0x89, 0xB8, 0x2F, 0x6F, 0x37, 0x48, 0x30, 0x61, 0xBD, 0x38, @@ -65316,7 +65543,7 @@ const unsigned char timelib_timezone_db_data_builtin[711319] = { 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0x9A, 0x6C, 0x7D, 0xC8, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x00, 0xCC, 0x48, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x94, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xAD, 0x13, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x79, 0x73, 0x40, 0x00, -0x00, 0x00, 0x00, 0x10, 0x28, 0xCA, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x10, 0xED, 0x3A, 0x40, 0x00, +0x00, 0x00, 0x00, 0x10, 0x28, 0xCA, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA9, 0xFD, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x11, 0xAD, 0xBC, 0x48, 0x00, 0x00, 0x00, 0x00, 0x12, 0x45, 0x4A, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, 0xEC, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x14, 0x2D, 0x15, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x28, 0x20, 0x76, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x28, 0xDB, 0x9D, 0xB8, 0x00, @@ -70844,4 +71071,4 @@ const unsigned char timelib_timezone_db_data_builtin[711319] = { }; #endif -const timelib_tzdb timezonedb_builtin = { "2025.1", 597, timezonedb_idx_builtin, timelib_timezone_db_data_builtin }; +const timelib_tzdb timezonedb_builtin = { "2025.2", 598, timezonedb_idx_builtin, timelib_timezone_db_data_builtin }; diff --git a/ext/date/php_date.c b/ext/date/php_date.c index ed89c9d494a6f..99b0fc3c952c0 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -673,7 +673,7 @@ static const char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib /* }}} */ /* {{{ date_format - (gm)date helper */ -static zend_string *date_format(const char *format, size_t format_len, timelib_time *t, bool localtime) +static zend_string *date_format(const char *format, size_t format_len, const timelib_time *t, bool localtime) { smart_str string = {0}; size_t i; @@ -845,7 +845,7 @@ static zend_string *date_format(const char *format, size_t format_len, timelib_t return string.s; } -PHPAPI zend_string *php_format_date_obj(const char *format, size_t format_len, php_date_obj *date_obj) +PHPAPI zend_string *php_format_date_obj(const char *format, size_t format_len, const php_date_obj *date_obj) { if (!date_obj->time) { return NULL; @@ -2807,7 +2807,7 @@ PHP_METHOD(DateTimeImmutable, createFromTimestamp) } /* }}} */ -static bool php_date_initialize_from_hash(php_date_obj **dateobj, HashTable *myht) +static bool php_date_initialize_from_hash(php_date_obj **dateobj, const HashTable *myht) { zval *z_date; zval *z_timezone_type; @@ -2948,7 +2948,7 @@ PHP_METHOD(DateTimeImmutable, __serialize) } /* }}} */ -static bool date_time_is_internal_property(zend_string *name) +static bool date_time_is_internal_property(const zend_string *name) { if ( zend_string_equals_literal(name, "date") || @@ -2960,7 +2960,7 @@ static bool date_time_is_internal_property(zend_string *name) return 0; } -static void restore_custom_datetime_properties(zval *object, HashTable *myht) +static void restore_custom_datetime_properties(zval *object, const HashTable *myht) { zend_string *prop_name; zval *prop_val; @@ -2978,15 +2978,13 @@ PHP_METHOD(DateTime, __unserialize) { zval *object = ZEND_THIS; php_date_obj *dateobj; - zval *array; HashTable *myht; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(array) + Z_PARAM_ARRAY_HT(myht) ZEND_PARSE_PARAMETERS_END(); dateobj = Z_PHPDATE_P(object); - myht = Z_ARRVAL_P(array); if (!php_date_initialize_from_hash(&dateobj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DateTime object"); @@ -3002,15 +3000,13 @@ PHP_METHOD(DateTimeImmutable, __unserialize) { zval *object = ZEND_THIS; php_date_obj *dateobj; - zval *array; HashTable *myht; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(array) + Z_PARAM_ARRAY_HT(myht) ZEND_PARSE_PARAMETERS_END(); dateobj = Z_PHPDATE_P(object); - myht = Z_ARRVAL_P(array); if (!php_date_initialize_from_hash(&dateobj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DateTimeImmutable object"); @@ -3027,7 +3023,7 @@ static void php_do_date_time_wakeup(INTERNAL_FUNCTION_PARAMETERS, const char *cl { zval *object = ZEND_THIS; php_date_obj *dateobj; - HashTable *myht; + const HashTable *myht; ZEND_PARSE_PARAMETERS_NONE(); @@ -3057,7 +3053,7 @@ PHP_METHOD(DateTimeImmutable, __wakeup) /* }}} */ /* Helper function used to add an associative array of warnings and errors to a zval */ -static void zval_from_error_container(zval *z, timelib_error_container *error) /* {{{ */ +static void zval_from_error_container(zval *z, const timelib_error_container *error) /* {{{ */ { int i; zval element; @@ -3498,7 +3494,7 @@ PHP_METHOD(DateTimeImmutable, sub) } /* }}} */ -static void set_timezone_from_timelib_time(php_timezone_obj *tzobj, timelib_time *t) +static void set_timezone_from_timelib_time(php_timezone_obj *tzobj, const timelib_time *t) { /* Free abbreviation if already set */ if (tzobj->initialized && tzobj->type == TIMELIB_ZONETYPE_ABBR) { @@ -4057,7 +4053,7 @@ PHP_METHOD(DateTimeZone, __construct) } /* }}} */ -static bool php_date_timezone_initialize_from_hash(zval **return_value, php_timezone_obj **tzobj, HashTable *myht) /* {{{ */ +static bool php_date_timezone_initialize_from_hash(zval **return_value, php_timezone_obj **tzobj, const HashTable *myht) /* {{{ */ { zval *z_timezone_type; @@ -4087,15 +4083,12 @@ static bool php_date_timezone_initialize_from_hash(zval **return_value, php_time PHP_METHOD(DateTimeZone, __set_state) { php_timezone_obj *tzobj; - zval *array; HashTable *myht; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(array) + Z_PARAM_ARRAY_HT(myht) ZEND_PARSE_PARAMETERS_END(); - myht = Z_ARRVAL_P(array); - php_date_instantiate(date_ce_timezone, return_value); tzobj = Z_PHPTIMEZONE_P(return_value); if (!php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht)) { @@ -4110,7 +4103,7 @@ PHP_METHOD(DateTimeZone, __wakeup) { zval *object = ZEND_THIS; php_timezone_obj *tzobj; - HashTable *myht; + const HashTable *myht; ZEND_PARSE_PARAMETERS_NONE(); @@ -4145,7 +4138,7 @@ PHP_METHOD(DateTimeZone, __serialize) } /* }}} */ -static bool date_timezone_is_internal_property(zend_string *name) +static bool date_timezone_is_internal_property(const zend_string *name) { if ( zend_string_equals_literal(name, "timezone_type") || @@ -4156,7 +4149,7 @@ static bool date_timezone_is_internal_property(zend_string *name) return 0; } -static void restore_custom_datetimezone_properties(zval *object, HashTable *myht) +static void restore_custom_datetimezone_properties(zval *object, const HashTable *myht) { zend_string *prop_name; zval *prop_val; @@ -4174,15 +4167,13 @@ PHP_METHOD(DateTimeZone, __unserialize) { zval *object = ZEND_THIS; php_timezone_obj *tzobj; - zval *array; HashTable *myht; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(array) + Z_PARAM_ARRAY_HT(myht) ZEND_PARSE_PARAMETERS_END(); tzobj = Z_PHPTIMEZONE_P(object); - myht = Z_ARRVAL_P(array); if (!php_date_timezone_initialize_from_hash(&object, &tzobj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DateTimeZone object"); @@ -4422,7 +4413,7 @@ PHP_FUNCTION(timezone_location_get) } /* }}} */ -static bool date_interval_initialize(timelib_rel_time **rt, /*const*/ char *format, size_t format_length) /* {{{ */ +static bool date_interval_initialize(timelib_rel_time **rt, const char *format, size_t format_length) /* {{{ */ { timelib_time *b = NULL, *e = NULL; timelib_rel_time *p = NULL; @@ -4576,7 +4567,9 @@ static zval *date_interval_get_property_ptr_ptr(zend_object *object, zend_string zend_string_equals_literal(name, "days") || zend_string_equals_literal(name, "invert") ) { /* Fallback to read_property. */ - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } ret = NULL; } else { ret = zend_std_get_property_ptr_ptr(object, name, type, cache_slot); @@ -4607,10 +4600,10 @@ PHP_METHOD(DateInterval, __construct) } /* }}} */ -static void php_date_interval_initialize_from_hash(zval **return_value, php_interval_obj **intobj, HashTable *myht) /* {{{ */ +static void php_date_interval_initialize_from_hash(zval **return_value, php_interval_obj **intobj, const HashTable *myht) /* {{{ */ { /* If we have a date_string, use that instead */ - zval *date_str = zend_hash_str_find(myht, "date_string", strlen("date_string")); + const zval *date_str = zend_hash_str_find(myht, "date_string", strlen("date_string")); if (date_str && Z_TYPE_P(date_str) == IS_STRING) { timelib_time *time; timelib_error_container *err = NULL; @@ -4708,7 +4701,7 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte PHP_DATE_INTERVAL_READ_PROPERTY("i", i, timelib_sll, -1) PHP_DATE_INTERVAL_READ_PROPERTY("s", s, timelib_sll, -1) { - zval *z_arg = zend_hash_str_find(myht, "f", sizeof("f") - 1); + const zval *z_arg = zend_hash_str_find(myht, "f", sizeof("f") - 1); if (z_arg) { (*intobj)->diff->us = zend_dval_to_lval(zval_get_double(z_arg) * 1000000.0); } @@ -4723,7 +4716,7 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte PHP_DATE_INTERVAL_READ_PROPERTY("have_weekday_relative", have_weekday_relative, unsigned int, 0); PHP_DATE_INTERVAL_READ_PROPERTY("have_special_relative", have_special_relative, unsigned int, 0); { - zval *z_arg = zend_hash_str_find(myht, "civil_or_wall", sizeof("civil_or_wall") - 1); + const zval *z_arg = zend_hash_str_find(myht, "civil_or_wall", sizeof("civil_or_wall") - 1); (*intobj)->civil_or_wall = PHP_DATE_CIVIL; if (z_arg) { zend_long val = zval_get_long(z_arg); @@ -4738,15 +4731,12 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte PHP_METHOD(DateInterval, __set_state) { php_interval_obj *intobj; - zval *array; HashTable *myht; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(array) + Z_PARAM_ARRAY_HT(myht) ZEND_PARSE_PARAMETERS_END(); - myht = Z_ARRVAL_P(array); - php_date_instantiate(date_ce_interval, return_value); intobj = Z_PHPINTERVAL_P(return_value); php_date_interval_initialize_from_hash(&return_value, &intobj, myht); @@ -4773,7 +4763,7 @@ PHP_METHOD(DateInterval, __serialize) } /* }}} */ -static bool date_interval_is_internal_property(zend_string *name) +static bool date_interval_is_internal_property(const zend_string *name) { if ( zend_string_equals_literal(name, "date_string") || @@ -4793,7 +4783,7 @@ static bool date_interval_is_internal_property(zend_string *name) return 0; } -static void restore_custom_dateinterval_properties(zval *object, HashTable *myht) +static void restore_custom_dateinterval_properties(zval *object, const HashTable *myht) { zend_string *prop_name; zval *prop_val; @@ -4812,15 +4802,13 @@ PHP_METHOD(DateInterval, __unserialize) { zval *object = ZEND_THIS; php_interval_obj *intervalobj; - zval *array; HashTable *myht; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(array) + Z_PARAM_ARRAY_HT(myht) ZEND_PARSE_PARAMETERS_END(); intervalobj = Z_PHPINTERVAL_P(object); - myht = Z_ARRVAL_P(array); php_date_interval_initialize_from_hash(&object, &intervalobj, myht); restore_custom_dateinterval_properties(object, myht); @@ -4832,7 +4820,7 @@ PHP_METHOD(DateInterval, __wakeup) { zval *object = ZEND_THIS; php_interval_obj *intobj; - HashTable *myht; + const HashTable *myht; ZEND_PARSE_PARAMETERS_NONE(); @@ -4924,7 +4912,7 @@ PHP_METHOD(DateInterval, createFromDateString) /* }}} */ /* {{{ date_interval_format - */ -static zend_string *date_interval_format(char *format, size_t format_len, timelib_rel_time *t) +static zend_string *date_interval_format(const char *format, size_t format_len, timelib_rel_time *t) { smart_str string = {0}; size_t i; @@ -4998,7 +4986,7 @@ PHP_FUNCTION(date_interval_format) { zval *object; php_interval_obj *diobj; - char *format; + const char *format; size_t format_len; if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &object, date_ce_interval, &format, &format_len) == FAILURE) { @@ -5011,7 +4999,7 @@ PHP_FUNCTION(date_interval_format) } /* }}} */ -static bool date_period_initialize(timelib_time **st, timelib_time **et, timelib_rel_time **d, zend_long *recurrences, /*const*/ char *format, size_t format_length) /* {{{ */ +static bool date_period_initialize(timelib_time **st, timelib_time **et, timelib_rel_time **d, zend_long *recurrences, const char *format, size_t format_length) /* {{{ */ { timelib_time *b = NULL, *e = NULL; timelib_rel_time *p = NULL; @@ -5044,7 +5032,7 @@ static bool date_period_initialize(timelib_time **st, timelib_time **et, timelib return retval; } /* }}} */ -static bool date_period_init_iso8601_string(php_period_obj *dpobj, zend_class_entry* base_ce, char *isostr, size_t isostr_len, zend_long options, zend_long *recurrences) +static bool date_period_init_iso8601_string(php_period_obj *dpobj, zend_class_entry* base_ce, const char *isostr, size_t isostr_len, zend_long *recurrences) { if (!date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), recurrences, isostr, isostr_len)) { return false; @@ -5130,7 +5118,7 @@ PHP_METHOD(DatePeriod, createFromISO8601String) dpobj->current = NULL; - if (!date_period_init_iso8601_string(dpobj, date_ce_immutable, isostr, isostr_len, options, &recurrences)) { + if (!date_period_init_iso8601_string(dpobj, date_ce_immutable, isostr, isostr_len, &recurrences)) { RETURN_THROWS(); } @@ -5169,7 +5157,7 @@ PHP_METHOD(DatePeriod, __construct) RETURN_THROWS(); } - if (!date_period_init_iso8601_string(dpobj, date_ce_date, isostr, isostr_len, options, &recurrences)) { + if (!date_period_init_iso8601_string(dpobj, date_ce_date, isostr, isostr_len, &recurrences)) { RETURN_THROWS(); } } else { @@ -5305,7 +5293,7 @@ PHP_METHOD(DatePeriod, getIterator) zend_create_internal_iterator_zval(return_value, ZEND_THIS); } -static int check_id_allowed(char *id, zend_long what) /* {{{ */ +static bool check_id_allowed(const char *id, zend_long what) /* {{{ */ { if ((what & PHP_DATE_TIMEZONE_GROUP_AFRICA) && strncasecmp(id, "Africa/", 7) == 0) return 1; if ((what & PHP_DATE_TIMEZONE_GROUP_AMERICA) && strncasecmp(id, "America/", 8) == 0) return 1; @@ -5711,7 +5699,7 @@ static void date_period_object_to_hash(php_period_obj *period_obj, HashTable *pr zend_hash_str_update(props, "include_end_date", sizeof("include_end_date")-1, &zv); } -static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, HashTable *myht) /* {{{ */ +static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, const HashTable *myht) /* {{{ */ { zval *ht_entry; @@ -5835,15 +5823,12 @@ static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, Has PHP_METHOD(DatePeriod, __set_state) { php_period_obj *period_obj; - zval *array; HashTable *myht; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(array) + Z_PARAM_ARRAY_HT(myht) ZEND_PARSE_PARAMETERS_END(); - myht = Z_ARRVAL_P(array); - object_init_ex(return_value, date_ce_period); period_obj = Z_PHPPERIOD_P(return_value); if (!php_date_period_initialize_from_hash(period_obj, myht)) { @@ -5877,7 +5862,7 @@ PHP_METHOD(DatePeriod, __serialize) * Common for date_period_read_property(), date_period_write_property(), and * restore_custom_dateperiod_properties functions */ -static bool date_period_is_internal_property(zend_string *name) +static bool date_period_is_internal_property(const zend_string *name) { if ( zend_string_equals_literal(name, "start") || @@ -5894,7 +5879,7 @@ static bool date_period_is_internal_property(zend_string *name) } /* }}} */ -static void restore_custom_dateperiod_properties(zval *object, HashTable *myht) +static void restore_custom_dateperiod_properties(zval *object, const HashTable *myht) { zend_string *prop_name; zval *prop_val; @@ -5912,15 +5897,13 @@ PHP_METHOD(DatePeriod, __unserialize) { zval *object = ZEND_THIS; php_period_obj *period_obj; - zval *array; HashTable *myht; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(array) + Z_PARAM_ARRAY_HT(myht) ZEND_PARSE_PARAMETERS_END(); period_obj = Z_PHPPERIOD_P(object); - myht = Z_ARRVAL_P(array); if (!php_date_period_initialize_from_hash(period_obj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DatePeriod object"); @@ -5935,7 +5918,7 @@ PHP_METHOD(DatePeriod, __wakeup) { zval *object = ZEND_THIS; php_period_obj *period_obj; - HashTable *myht; + const HashTable *myht; ZEND_PARSE_PARAMETERS_NONE(); diff --git a/ext/date/php_date.h b/ext/date/php_date.h index f1b7c892001a9..f5f43bc7dfb0f 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -89,9 +89,9 @@ static inline php_timezone_obj *php_timezone_obj_from_obj(zend_object *obj) { struct _php_interval_obj { timelib_rel_time *diff; int civil_or_wall; + bool initialized; bool from_string; zend_string *date_string; - bool initialized; zend_object std; }; @@ -140,7 +140,7 @@ PHPAPI int php_idate(char format, time_t ts, bool localtime); PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, bool gm); PHPAPI zend_string *php_format_date(const char *format, size_t format_len, time_t ts, bool localtime); -PHPAPI zend_string *php_format_date_obj(const char *format, size_t format_len, php_date_obj *date_obj); +PHPAPI zend_string *php_format_date_obj(const char *format, size_t format_len, const php_date_obj *date_obj); /* Mechanism to set new TZ database */ PHPAPI void php_date_set_tzdb(timelib_tzdb *tzdb); diff --git a/ext/date/php_date.stub.php b/ext/date/php_date.stub.php index d0119aac88ad5..f375c60ff0a4c 100644 --- a/ext/date/php_date.stub.php +++ b/ext/date/php_date.stub.php @@ -524,29 +524,38 @@ public function getMicrosecond(): int {} public function diff(DateTimeInterface $targetObject, bool $absolute = false): DateInterval {} /** @tentative-return-type */ + #[\NoDiscard(message: "as DateTimeImmutable::modify() does not modify the object itself")] public function modify(string $modifier): DateTimeImmutable {} /** @tentative-return-type */ + #[\NoDiscard(message: "as DateTimeImmutable::add() does not modify the object itself")] public function add(DateInterval $interval): DateTimeImmutable {} /** @tentative-return-type */ + #[\NoDiscard(message: "as DateTimeImmutable::sub() does not modify the object itself")] public function sub(DateInterval $interval): DateTimeImmutable {} /** @tentative-return-type */ + #[\NoDiscard(message: "as DateTimeImmutable::setTimezone() does not modify the object itself")] public function setTimezone(DateTimeZone $timezone): DateTimeImmutable {} /** @tentative-return-type */ + #[\NoDiscard(message: "as DateTimeImmutable::setTime() does not modify the object itself")] public function setTime(int $hour, int $minute, int $second = 0, int $microsecond = 0): DateTimeImmutable {} /** @tentative-return-type */ + #[\NoDiscard(message: "as DateTimeImmutable::setDate() does not modify the object itself")] public function setDate(int $year, int $month, int $day): DateTimeImmutable {} /** @tentative-return-type */ + #[\NoDiscard(message: "as DateTimeImmutable::setISODate() does not modify the object itself")] public function setISODate(int $year, int $week, int $dayOfWeek = 1): DateTimeImmutable {} /** @tentative-return-type */ + #[\NoDiscard(message: "as DateTimeImmutable::setTimestamp() does not modify the object itself")] public function setTimestamp(int $timestamp): DateTimeImmutable {} + #[\NoDiscard(message: "as DateTimeImmutable::setMicrosecond() does not modify the object itself")] public function setMicrosecond(int $microsecond): static {} /** @tentative-return-type */ diff --git a/ext/date/php_date_arginfo.h b/ext/date/php_date_arginfo.h index 8ce0114206cfe..82e9f0f1718ae 100644 --- a/ext/date/php_date_arginfo.h +++ b/ext/date/php_date_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: d7a318f6fd85e23c6352323e03c323035a511738 */ + * Stub hash: 093743b4fe7a698d1262cc1a81b60a85064fdccb */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0) @@ -725,15 +725,15 @@ static const zend_function_entry class_DateTimeImmutable_methods[] = { ZEND_RAW_FENTRY("getTimestamp", zif_date_timestamp_get, arginfo_class_DateTimeImmutable_getTimestamp, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("getMicrosecond", zim_DateTime_getMicrosecond, arginfo_class_DateTimeImmutable_getMicrosecond, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("diff", zif_date_diff, arginfo_class_DateTimeImmutable_diff, ZEND_ACC_PUBLIC, NULL, NULL) - ZEND_ME(DateTimeImmutable, modify, arginfo_class_DateTimeImmutable_modify, ZEND_ACC_PUBLIC) - ZEND_ME(DateTimeImmutable, add, arginfo_class_DateTimeImmutable_add, ZEND_ACC_PUBLIC) - ZEND_ME(DateTimeImmutable, sub, arginfo_class_DateTimeImmutable_sub, ZEND_ACC_PUBLIC) - ZEND_ME(DateTimeImmutable, setTimezone, arginfo_class_DateTimeImmutable_setTimezone, ZEND_ACC_PUBLIC) - ZEND_ME(DateTimeImmutable, setTime, arginfo_class_DateTimeImmutable_setTime, ZEND_ACC_PUBLIC) - ZEND_ME(DateTimeImmutable, setDate, arginfo_class_DateTimeImmutable_setDate, ZEND_ACC_PUBLIC) - ZEND_ME(DateTimeImmutable, setISODate, arginfo_class_DateTimeImmutable_setISODate, ZEND_ACC_PUBLIC) - ZEND_ME(DateTimeImmutable, setTimestamp, arginfo_class_DateTimeImmutable_setTimestamp, ZEND_ACC_PUBLIC) - ZEND_ME(DateTimeImmutable, setMicrosecond, arginfo_class_DateTimeImmutable_setMicrosecond, ZEND_ACC_PUBLIC) + ZEND_ME(DateTimeImmutable, modify, arginfo_class_DateTimeImmutable_modify, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) + ZEND_ME(DateTimeImmutable, add, arginfo_class_DateTimeImmutable_add, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) + ZEND_ME(DateTimeImmutable, sub, arginfo_class_DateTimeImmutable_sub, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) + ZEND_ME(DateTimeImmutable, setTimezone, arginfo_class_DateTimeImmutable_setTimezone, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) + ZEND_ME(DateTimeImmutable, setTime, arginfo_class_DateTimeImmutable_setTime, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) + ZEND_ME(DateTimeImmutable, setDate, arginfo_class_DateTimeImmutable_setDate, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) + ZEND_ME(DateTimeImmutable, setISODate, arginfo_class_DateTimeImmutable_setISODate, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) + ZEND_ME(DateTimeImmutable, setTimestamp, arginfo_class_DateTimeImmutable_setTimestamp, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) + ZEND_ME(DateTimeImmutable, setMicrosecond, arginfo_class_DateTimeImmutable_setMicrosecond, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) ZEND_ME(DateTimeImmutable, createFromMutable, arginfo_class_DateTimeImmutable_createFromMutable, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME(DateTimeImmutable, createFromInterface, arginfo_class_DateTimeImmutable_createFromInterface, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_FE_END @@ -989,6 +989,88 @@ static zend_class_entry *register_class_DateTimeImmutable(zend_class_entry *clas class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); zend_class_implements(class_entry, 1, class_entry_DateTimeInterface); + + zend_string *attribute_name_NoDiscard_func_modify_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1); + zend_attribute *attribute_NoDiscard_func_modify_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "modify", sizeof("modify") - 1), attribute_name_NoDiscard_func_modify_0, 1); + zend_string_release(attribute_name_NoDiscard_func_modify_0); + zval attribute_NoDiscard_func_modify_0_arg0; + zend_string *attribute_NoDiscard_func_modify_0_arg0_str = zend_string_init("as DateTimeImmutable::modify() does not modify the object itself", strlen("as DateTimeImmutable::modify() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_modify_0_arg0, attribute_NoDiscard_func_modify_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_NoDiscard_func_modify_0->args[0].value, &attribute_NoDiscard_func_modify_0_arg0); + attribute_NoDiscard_func_modify_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_NoDiscard_func_add_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1); + zend_attribute *attribute_NoDiscard_func_add_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "add", sizeof("add") - 1), attribute_name_NoDiscard_func_add_0, 1); + zend_string_release(attribute_name_NoDiscard_func_add_0); + zval attribute_NoDiscard_func_add_0_arg0; + zend_string *attribute_NoDiscard_func_add_0_arg0_str = zend_string_init("as DateTimeImmutable::add() does not modify the object itself", strlen("as DateTimeImmutable::add() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_add_0_arg0, attribute_NoDiscard_func_add_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_NoDiscard_func_add_0->args[0].value, &attribute_NoDiscard_func_add_0_arg0); + attribute_NoDiscard_func_add_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_NoDiscard_func_sub_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1); + zend_attribute *attribute_NoDiscard_func_sub_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "sub", sizeof("sub") - 1), attribute_name_NoDiscard_func_sub_0, 1); + zend_string_release(attribute_name_NoDiscard_func_sub_0); + zval attribute_NoDiscard_func_sub_0_arg0; + zend_string *attribute_NoDiscard_func_sub_0_arg0_str = zend_string_init("as DateTimeImmutable::sub() does not modify the object itself", strlen("as DateTimeImmutable::sub() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_sub_0_arg0, attribute_NoDiscard_func_sub_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_NoDiscard_func_sub_0->args[0].value, &attribute_NoDiscard_func_sub_0_arg0); + attribute_NoDiscard_func_sub_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_NoDiscard_func_settimezone_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1); + zend_attribute *attribute_NoDiscard_func_settimezone_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "settimezone", sizeof("settimezone") - 1), attribute_name_NoDiscard_func_settimezone_0, 1); + zend_string_release(attribute_name_NoDiscard_func_settimezone_0); + zval attribute_NoDiscard_func_settimezone_0_arg0; + zend_string *attribute_NoDiscard_func_settimezone_0_arg0_str = zend_string_init("as DateTimeImmutable::setTimezone() does not modify the object itself", strlen("as DateTimeImmutable::setTimezone() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_settimezone_0_arg0, attribute_NoDiscard_func_settimezone_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_NoDiscard_func_settimezone_0->args[0].value, &attribute_NoDiscard_func_settimezone_0_arg0); + attribute_NoDiscard_func_settimezone_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_NoDiscard_func_settime_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1); + zend_attribute *attribute_NoDiscard_func_settime_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "settime", sizeof("settime") - 1), attribute_name_NoDiscard_func_settime_0, 1); + zend_string_release(attribute_name_NoDiscard_func_settime_0); + zval attribute_NoDiscard_func_settime_0_arg0; + zend_string *attribute_NoDiscard_func_settime_0_arg0_str = zend_string_init("as DateTimeImmutable::setTime() does not modify the object itself", strlen("as DateTimeImmutable::setTime() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_settime_0_arg0, attribute_NoDiscard_func_settime_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_NoDiscard_func_settime_0->args[0].value, &attribute_NoDiscard_func_settime_0_arg0); + attribute_NoDiscard_func_settime_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_NoDiscard_func_setdate_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1); + zend_attribute *attribute_NoDiscard_func_setdate_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "setdate", sizeof("setdate") - 1), attribute_name_NoDiscard_func_setdate_0, 1); + zend_string_release(attribute_name_NoDiscard_func_setdate_0); + zval attribute_NoDiscard_func_setdate_0_arg0; + zend_string *attribute_NoDiscard_func_setdate_0_arg0_str = zend_string_init("as DateTimeImmutable::setDate() does not modify the object itself", strlen("as DateTimeImmutable::setDate() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_setdate_0_arg0, attribute_NoDiscard_func_setdate_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_NoDiscard_func_setdate_0->args[0].value, &attribute_NoDiscard_func_setdate_0_arg0); + attribute_NoDiscard_func_setdate_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_NoDiscard_func_setisodate_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1); + zend_attribute *attribute_NoDiscard_func_setisodate_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "setisodate", sizeof("setisodate") - 1), attribute_name_NoDiscard_func_setisodate_0, 1); + zend_string_release(attribute_name_NoDiscard_func_setisodate_0); + zval attribute_NoDiscard_func_setisodate_0_arg0; + zend_string *attribute_NoDiscard_func_setisodate_0_arg0_str = zend_string_init("as DateTimeImmutable::setISODate() does not modify the object itself", strlen("as DateTimeImmutable::setISODate() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_setisodate_0_arg0, attribute_NoDiscard_func_setisodate_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_NoDiscard_func_setisodate_0->args[0].value, &attribute_NoDiscard_func_setisodate_0_arg0); + attribute_NoDiscard_func_setisodate_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_NoDiscard_func_settimestamp_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1); + zend_attribute *attribute_NoDiscard_func_settimestamp_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "settimestamp", sizeof("settimestamp") - 1), attribute_name_NoDiscard_func_settimestamp_0, 1); + zend_string_release(attribute_name_NoDiscard_func_settimestamp_0); + zval attribute_NoDiscard_func_settimestamp_0_arg0; + zend_string *attribute_NoDiscard_func_settimestamp_0_arg0_str = zend_string_init("as DateTimeImmutable::setTimestamp() does not modify the object itself", strlen("as DateTimeImmutable::setTimestamp() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_settimestamp_0_arg0, attribute_NoDiscard_func_settimestamp_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_NoDiscard_func_settimestamp_0->args[0].value, &attribute_NoDiscard_func_settimestamp_0_arg0); + attribute_NoDiscard_func_settimestamp_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_NoDiscard_func_setmicrosecond_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1); + zend_attribute *attribute_NoDiscard_func_setmicrosecond_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "setmicrosecond", sizeof("setmicrosecond") - 1), attribute_name_NoDiscard_func_setmicrosecond_0, 1); + zend_string_release(attribute_name_NoDiscard_func_setmicrosecond_0); + zval attribute_NoDiscard_func_setmicrosecond_0_arg0; + zend_string *attribute_NoDiscard_func_setmicrosecond_0_arg0_str = zend_string_init("as DateTimeImmutable::setMicrosecond() does not modify the object itself", strlen("as DateTimeImmutable::setMicrosecond() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_setmicrosecond_0_arg0, attribute_NoDiscard_func_setmicrosecond_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_NoDiscard_func_setmicrosecond_0->args[0].value, &attribute_NoDiscard_func_setmicrosecond_0_arg0); + attribute_NoDiscard_func_setmicrosecond_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + return class_entry; } diff --git a/ext/date/tests/gh18304.phpt b/ext/date/tests/gh18304.phpt new file mode 100644 index 0000000000000..4bab058a7ec4a --- /dev/null +++ b/ext/date/tests/gh18304.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault) +--CREDITS-- +orose-assetgo +--FILE-- +$field += $i; +var_dump($di); +?> +--EXPECT-- +object(DateInterval)#1 (10) { + ["y"]=> + int(0) + ["m"]=> + int(0) + ["d"]=> + int(1) + ["h"]=> + int(0) + ["i"]=> + int(0) + ["s"]=> + int(0) + ["f"]=> + float(0) + ["invert"]=> + int(0) + ["days"]=> + bool(false) + ["from_string"]=> + bool(false) +} diff --git a/ext/dba/dba.c b/ext/dba/dba.c index 4ef8df7478ac5..086998973e20a 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -1,5 +1,5 @@ /* - +----------------------------------------------------------------------+ ++----------------------------------------------------------------------+ | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | @@ -57,6 +57,7 @@ ZEND_BEGIN_MODULE_GLOBALS(dba) const char *default_handler; const dba_handler *default_hptr; HashTable connections; + unsigned int connection_counter; ZEND_END_MODULE_GLOBALS(dba) ZEND_DECLARE_MODULE_GLOBALS(dba) @@ -91,7 +92,7 @@ ZEND_GET_MODULE(dba) #endif /* {{{ php_dba_make_key */ -static zend_string* php_dba_make_key(HashTable *key) +static zend_string* php_dba_make_key(const HashTable *key) { zval *group, *name; zend_string *group_str, *name_str; @@ -434,10 +435,9 @@ PHP_MSHUTDOWN_FUNCTION(dba) /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(dba) { - const dba_handler *hptr; smart_str handlers = {0}; - for(hptr = handler; hptr->name; hptr++) { + for (const dba_handler *hptr = handler; hptr->name; hptr++) { smart_str_appends(&handlers, hptr->name); smart_str_appendc(&handlers, ' '); } @@ -569,7 +569,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) } zend_string *resource_key = zend_strpprintf(0, - "dba_%d_%s_%s_%s", persistent, ZSTR_VAL(path), ZSTR_VAL(mode), handler_str ? ZSTR_VAL(handler_str) : "" + "dba_%d_%u_%s_%s_%s", persistent, persistent ? 0 : DBA_G(connection_counter)++, ZSTR_VAL(path), ZSTR_VAL(mode), handler_str ? ZSTR_VAL(handler_str) : "" ); if (persistent) { @@ -857,9 +857,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) } if (!connection->info->lock.fp) { /* stream operation already wrote an error message */ - zend_string_release_ex(resource_key, /* persistent */ false); - zval_ptr_dtor(return_value); - RETURN_FALSE; + goto fail; } if (!error && !php_stream_supports_lock(connection->info->lock.fp)) { error = "Stream does not support locking"; @@ -878,9 +876,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) } if (!connection->info->fp) { /* stream operation already wrote an error message */ - zend_string_release_ex(resource_key, /* persistent */ false); - zval_ptr_dtor(return_value); - RETURN_FALSE; + goto fail; } if (hptr->flags & (DBA_NO_APPEND|DBA_CAST_AS_FD)) { /* Needed because some systems do not allow to write to the original @@ -888,9 +884,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) */ if (SUCCESS != php_stream_cast(connection->info->fp, PHP_STREAM_AS_FD, (void*)&connection->info->fd, 1)) { php_error_docref(NULL, E_WARNING, "Could not cast stream"); - zend_string_release_ex(resource_key, /* persistent */ false); - zval_ptr_dtor(return_value); - RETURN_FALSE; + goto fail; #ifdef F_SETFL } else if (modenr == DBA_CREAT) { int flags = fcntl(connection->info->fd, F_GETFL); @@ -924,9 +918,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) php_error_docref(NULL, E_WARNING, "Driver initialization failed for handler: %s", hptr->name); } } - zend_string_release_ex(resource_key, /* persistent */ false); - zval_ptr_dtor(return_value); - RETURN_FALSE; + goto fail; } connection->info->hnd = hptr; @@ -935,6 +927,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if (zend_register_persistent_resource_ex(connection->hash, connection->info, le_pdb) == NULL) { php_error_docref(NULL, E_WARNING, "Could not register persistent resource"); zend_string_release_ex(resource_key, /* persistent */ false); + dba_close_connection(connection); zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -942,6 +935,14 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) zend_hash_add_new(&DBA_G(connections), connection->hash, return_value); zend_string_release_ex(resource_key, /* persistent */ false); + return; +fail: + zend_string_release_ex(resource_key, /* persistent */ false); + zend_string_release_ex(connection->hash, persistent); + dba_close_info(connection->info); + connection->info = NULL; + zval_ptr_dtor(return_value); + RETURN_FALSE; } /* }}} */ @@ -1251,7 +1252,6 @@ PHP_FUNCTION(dba_sync) /* {{{ List configured database handlers */ PHP_FUNCTION(dba_handlers) { - const dba_handler *hptr; bool full_info = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &full_info) == FAILURE) { @@ -1260,7 +1260,7 @@ PHP_FUNCTION(dba_handlers) array_init(return_value); - for(hptr = handler; hptr->name; hptr++) { + for (const dba_handler *hptr = handler; hptr->name; hptr++) { if (full_info) { // TODO: avoid reallocation ??? char *str = hptr->info(hptr, NULL); diff --git a/ext/dba/tests/dba_duplicateopen.phpt b/ext/dba/tests/dba_duplicateopen.phpt new file mode 100644 index 0000000000000..7068981f1a3c8 --- /dev/null +++ b/ext/dba/tests/dba_duplicateopen.phpt @@ -0,0 +1,34 @@ +--TEST-- +DBA open same read only file multiple times +--EXTENSIONS-- +dba +--SKIPIF-- + +--CONFLICTS-- +test.cdb +--FILE-- + +--EXPECT-- +database handler: cdb +1122 diff --git a/ext/dba/tests/gh18247.phpt b/ext/dba/tests/gh18247.phpt new file mode 100644 index 0000000000000..bb757452321d9 --- /dev/null +++ b/ext/dba/tests/gh18247.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-18247: dba_open() memory leak on invalid path +--EXTENSIONS-- +dba +--FILE-- + +--EXPECTF-- + +Warning: dba_popen(/inexistent): Failed to open stream: No such file or directory in %s on line %d +bool(false) diff --git a/ext/dl_test/dl_test.c b/ext/dl_test/dl_test.c index 0983e7d62d8cb..10afdb0720f2d 100644 --- a/ext/dl_test/dl_test.c +++ b/ext/dl_test/dl_test.c @@ -92,10 +92,22 @@ PHP_METHOD(DlTest, test) RETURN_STR(retval); } +PHP_METHOD(DlTestSuperClass, test) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + RETURN_NULL(); +} + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(dl_test) { + zend_class_entry *ce; + register_class_DlTest(); + ce = register_class_DlTestSuperClass(); + register_class_DlTestSubClass(ce); + register_class_DlTestAliasedClass(); /* Test backwards compatibility */ if (getenv("PHP_DL_TEST_USE_OLD_REGISTER_INI_ENTRIES")) { diff --git a/ext/dl_test/dl_test.stub.php b/ext/dl_test/dl_test.stub.php index 7adfba527bbb4..9c3bbac6b267d 100644 --- a/ext/dl_test/dl_test.stub.php +++ b/ext/dl_test/dl_test.stub.php @@ -5,6 +5,9 @@ * @undocumentable */ +/** @var int */ +const DL_TEST_CONST = 42; + function dl_test_test1(): void {} function dl_test_test2(string $str = ""): string {} @@ -13,5 +16,13 @@ class DlTest { public function test(string $str = ""): string {} } -/** @var int */ -const DL_TEST_CONST = 42; +class DlTestSuperClass { + public int $a; + public function test(string $str = ""): string {} +} + +class DlTestSubClass extends DlTestSuperClass { +} + +class DlTestAliasedClass { +} diff --git a/ext/dl_test/dl_test_arginfo.h b/ext/dl_test/dl_test_arginfo.h index 46476b9629062..1b3b65aa7e677 100644 --- a/ext/dl_test/dl_test_arginfo.h +++ b/ext/dl_test/dl_test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: fa6eadc4164fb7b0d9f7d873d47205bbe5a46cd8 */ + * Stub hash: 75bdb57a45060b123fe48003fef43d2af07726e1 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dl_test_test1, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() @@ -10,9 +10,12 @@ ZEND_END_ARG_INFO() #define arginfo_class_DlTest_test arginfo_dl_test_test2 +#define arginfo_class_DlTestSuperClass_test arginfo_dl_test_test2 + ZEND_FUNCTION(dl_test_test1); ZEND_FUNCTION(dl_test_test2); ZEND_METHOD(DlTest, test); +ZEND_METHOD(DlTestSuperClass, test); static const zend_function_entry ext_functions[] = { ZEND_FE(dl_test_test1, arginfo_dl_test_test1) @@ -25,6 +28,11 @@ static const zend_function_entry class_DlTest_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_DlTestSuperClass_methods[] = { + ZEND_ME(DlTestSuperClass, test, arginfo_class_DlTestSuperClass_test, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + static void register_dl_test_symbols(int module_number) { REGISTER_LONG_CONSTANT("DL_TEST_CONST", 42, CONST_PERSISTENT); @@ -39,3 +47,39 @@ static zend_class_entry *register_class_DlTest(void) return class_entry; } + +static zend_class_entry *register_class_DlTestSuperClass(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DlTestSuperClass", class_DlTestSuperClass_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); + + zval property_a_default_value; + ZVAL_UNDEF(&property_a_default_value); + zend_string *property_a_name = zend_string_init("a", sizeof("a") - 1, 1); + zend_declare_typed_property(class_entry, property_a_name, &property_a_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_a_name); + + return class_entry; +} + +static zend_class_entry *register_class_DlTestSubClass(zend_class_entry *class_entry_DlTestSuperClass) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DlTestSubClass", NULL); + class_entry = zend_register_internal_class_with_flags(&ce, class_entry_DlTestSuperClass, 0); + + return class_entry; +} + +static zend_class_entry *register_class_DlTestAliasedClass(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DlTestAliasedClass", NULL); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); + + return class_entry; +} diff --git a/ext/dom/document.c b/ext/dom/document.c index 853275e3e232d..c7a8582e0872c 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -1665,14 +1665,28 @@ PHP_METHOD(Dom_XMLDocument, saveXml) } /* }}} end dom_document_savexml */ +static void dom_xinclude_strip_references_for_attributes(xmlNodePtr basep) +{ + for (xmlAttrPtr prop = basep->properties; prop; prop = prop->next) { + php_libxml_node_free_resource((xmlNodePtr) prop); + for (xmlNodePtr child = prop->children; child; child = child->next) { + php_libxml_node_free_resource(child); + } + } +} + static void dom_xinclude_strip_references(xmlNodePtr basep) { php_libxml_node_free_resource(basep); + dom_xinclude_strip_references_for_attributes(basep); xmlNodePtr current = basep->children; while (current) { php_libxml_node_free_resource(current); + if (current->type == XML_ELEMENT_NODE) { + dom_xinclude_strip_references_for_attributes(current); + } current = php_dom_next_in_tree_order(current, basep); } } diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c index 7468c3efaf4e7..a0797967d1e76 100644 --- a/ext/dom/dom_iterators.c +++ b/ext/dom/dom_iterators.c @@ -132,7 +132,7 @@ static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key) /* Only dtd named node maps, i.e. the ones based on a libxml hash table or attribute collections, * are keyed by the name because in that case the name is unique. */ if (!objmap->ht && objmap->nodetype != XML_ATTRIBUTE_NODE) { - ZVAL_LONG(key, iter->index); + ZVAL_LONG(key, iterator->index); } else { dom_object *intern = Z_DOMOBJ_P(&iterator->curobj); @@ -179,6 +179,8 @@ static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */ return; } + iterator->index++; + dom_object *intern = Z_DOMOBJ_P(&iterator->curobj); dom_nnodemap_object *objmap = php_dom_iterator_get_nnmap(iterator); @@ -187,9 +189,8 @@ static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */ objmap->nodetype != XML_NOTATION_NODE) { if (objmap->nodetype == DOM_NODESET) { HashTable *nodeht = Z_ARRVAL_P(&objmap->baseobj_zv); - zval *entry; - zend_hash_move_forward_ex(nodeht, &iterator->pos); - if ((entry = zend_hash_get_current_data_ex(nodeht, &iterator->pos))) { + zval *entry = zend_hash_index_find(nodeht, iterator->index); + if (entry) { zval_ptr_dtor(&iterator->curobj); ZVAL_COPY(&iterator->curobj, entry); return; @@ -203,7 +204,7 @@ static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */ php_dom_mark_cache_tag_up_to_date_from_doc_ref(&iterator->cache_tag, intern->document); curnode = dom_fetch_first_iteration_item(objmap); zend_ulong index = 0; - while (curnode != NULL && index++ < iter->index) { + while (curnode != NULL && index++ < iterator->index) { curnode = curnode->next; } } else { @@ -224,15 +225,15 @@ static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */ previndex = 0; curnode = php_dom_first_child_of_container_node(basenode); } else { - previndex = iter->index - 1; + previndex = iterator->index - 1; curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node; } curnode = dom_get_elements_by_tag_name_ns_raw( - basenode, curnode, objmap->ns, objmap->local, objmap->local_lower, &previndex, iter->index); + basenode, curnode, objmap->ns, objmap->local, objmap->local_lower, &previndex, iterator->index); } } } else { - curnode = php_dom_libxml_hash_iter(objmap, iter->index); + curnode = php_dom_libxml_hash_iter(objmap, iterator->index); } } @@ -261,32 +262,28 @@ zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, i dom_object *intern; dom_nnodemap_object *objmap; xmlNodePtr curnode=NULL; - HashTable *nodeht; - zval *entry; php_dom_iterator *iterator; if (by_ref) { zend_throw_error(NULL, "An iterator cannot be used with foreach by reference"); return NULL; } - iterator = emalloc(sizeof(php_dom_iterator)); + iterator = emalloc(sizeof(*iterator)); + memset(iterator, 0, sizeof(*iterator)); zend_iterator_init(&iterator->intern); - iterator->cache_tag.modification_nr = 0; ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object)); iterator->intern.funcs = &php_dom_iterator_funcs; - ZVAL_UNDEF(&iterator->curobj); - intern = Z_DOMOBJ_P(object); objmap = (dom_nnodemap_object *)intern->ptr; if (objmap != NULL) { if (objmap->nodetype != XML_ENTITY_NODE && objmap->nodetype != XML_NOTATION_NODE) { if (objmap->nodetype == DOM_NODESET) { - nodeht = Z_ARRVAL_P(&objmap->baseobj_zv); - zend_hash_internal_pointer_reset_ex(nodeht, &iterator->pos); - if ((entry = zend_hash_get_current_data_ex(nodeht, &iterator->pos))) { + HashTable *nodeht = Z_ARRVAL_P(&objmap->baseobj_zv); + zval *entry = zend_hash_index_find(nodeht, 0); + if (entry) { ZVAL_COPY(&iterator->curobj, entry); } } else { diff --git a/ext/dom/html5_parser.c b/ext/dom/html5_parser.c index 0d7d2b9e7249d..f1dc2db53b25b 100644 --- a/ext/dom/html5_parser.c +++ b/ext/dom/html5_parser.c @@ -138,7 +138,9 @@ static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert( * If a prefix:name format is used, then the local name will be "prefix:name" and the prefix will be empty. * There is however still somewhat of a concept of namespaces. There are three: HTML (the default), SVG, and MATHML. */ lxb_dom_element_t *element = lxb_dom_interface_element(node); - const lxb_char_t *name = lxb_dom_element_local_name(element, NULL); + const lxb_char_t *name = lxb_dom_element_qualified_name(element, NULL); + ZEND_ASSERT(!element->node.prefix); + xmlNodePtr lxml_element = xmlNewDocNode(lxml_doc, NULL, name, NULL); if (UNEXPECTED(lxml_element == NULL)) { retval = LEXBOR_LIBXML2_BRIDGE_STATUS_OOM; @@ -203,7 +205,13 @@ static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert( for (lxb_dom_attr_t *attr = element->first_attr; attr != NULL; attr = attr->next) { /* Same namespace remark as for elements */ size_t local_name_length, value_length; - const lxb_char_t *local_name = lxb_dom_attr_local_name(attr, &local_name_length); + const lxb_char_t *local_name = lxb_dom_attr_qualified_name(attr, &local_name_length); + if (attr->node.prefix) { + const char *pos = strchr((const char *) local_name, ':'); + if (EXPECTED(pos)) { + local_name = (const lxb_char_t *) pos + 1; + } + } const lxb_char_t *value = lxb_dom_attr_value(attr, &value_length); if (UNEXPECTED(local_name_length >= INT_MAX || value_length >= INT_MAX)) { diff --git a/ext/dom/namespace_compat.c b/ext/dom/namespace_compat.c index 7a3bd68b0111a..ee32ec39dbeb3 100644 --- a/ext/dom/namespace_compat.c +++ b/ext/dom/namespace_compat.c @@ -180,7 +180,7 @@ PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(php return php_dom_libxml_ns_mapper_get_ns_raw_strings(mapper, prefix, uri); } -static xmlNsPtr php_dom_libxml_ns_mapper_store_and_normalize_parsed_ns(php_dom_libxml_ns_mapper *mapper, xmlNsPtr ns) +static void php_dom_libxml_ns_mapper_store_and_normalize_parsed_ns(php_dom_libxml_ns_mapper *mapper, xmlNsPtr ns) { ZEND_ASSERT(ns != NULL); @@ -198,16 +198,9 @@ static xmlNsPtr php_dom_libxml_ns_mapper_store_and_normalize_parsed_ns(php_dom_l prefix_len = xmlStrlen(ns->prefix); } - zval *zv = zend_hash_str_find_ptr(prefix_map, prefix, prefix_len); - if (zv != NULL) { - return Z_PTR_P(zv); - } - zval new_zv; DOM_Z_UNOWNED(&new_zv, ns); - zend_hash_str_add_new(prefix_map, prefix, prefix_len, &new_zv); - - return ns; + zend_hash_str_add(prefix_map, prefix, prefix_len, &new_zv); } typedef struct { diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 6bcee1bc23e15..0751284bdc976 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -357,7 +357,9 @@ static zval *dom_get_property_ptr_ptr(zend_object *object, zend_string *name, in return zend_std_get_property_ptr_ptr(object, name, type, cache_slot); } - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } return NULL; } @@ -367,13 +369,14 @@ static zend_always_inline const dom_prop_handler *dom_get_prop_handler(const dom if (obj->prop_handler != NULL) { if (cache_slot && *cache_slot == obj->prop_handler) { - hnd = *(cache_slot + 1); + hnd = cache_slot[1]; } if (!hnd) { hnd = zend_hash_find_ptr(obj->prop_handler, name); if (cache_slot) { - *cache_slot = obj->prop_handler; - *(cache_slot + 1) = (void *) hnd; + cache_slot[0] = obj->prop_handler; + cache_slot[1] = (void *) hnd; + cache_slot[2] = NULL; } } } diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index 1c21d8a64e1a9..31fec5a7cabcb 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -97,7 +97,9 @@ typedef struct dom_nnodemap_object { typedef struct { zend_object_iterator intern; zval curobj; - HashPosition pos; + /* intern->index is only updated for FE_* opcodes, not for e.g. unpacking, + * yet we need to track the position of the node relative to the start. */ + zend_ulong index; php_libxml_cache_tag cache_tag; } php_dom_iterator; diff --git a/ext/dom/tests/DOMDocument_loadHTMLfile_variation1.phpt b/ext/dom/tests/DOMDocument_loadHTMLfile_variation1.phpt index b3ff73d1f3441..74c27e93d9dcc 100644 --- a/ext/dom/tests/DOMDocument_loadHTMLfile_variation1.phpt +++ b/ext/dom/tests/DOMDocument_loadHTMLfile_variation1.phpt @@ -6,6 +6,10 @@ Verifies that an warning message is showed if an empty document is loaded Antonio Diaz Ruiz --EXTENSIONS-- dom +--SKIPIF-- += 21400) die("skip libxml >= 2.14 no longer has this non-standard warning"); +?> --FILE-- U+0000 loadHTML($html); print($doc->saveHTML()); ?> ---EXPECT-- +--EXPECTF-- -U+0000 +U+0000 %r(�|)%r diff --git a/ext/dom/tests/bug78025.phpt b/ext/dom/tests/bug78025.phpt index 910f7728c3c2c..d6f84939c5f14 100644 --- a/ext/dom/tests/bug78025.phpt +++ b/ext/dom/tests/bug78025.phpt @@ -6,9 +6,8 @@ dom "; $dom = new DOMDocument; -$dom->loadHTML($htm); +$dom->loadHTML($htm, LIBXML_NOERROR); var_dump($dom->doctype->name); ?> --EXPECTF-- -Warning: DOMDocument::loadHTML(): htmlParseDocTypeDecl : no DOCTYPE name ! in Entity, line: 1 in %s on line %d string(0) "" diff --git a/ext/dom/tests/bug80268_2.phpt b/ext/dom/tests/bug80268_2.phpt index af8cf7faca5a5..dcde29e6835a7 100644 --- a/ext/dom/tests/bug80268_2.phpt +++ b/ext/dom/tests/bug80268_2.phpt @@ -9,13 +9,13 @@ if (LIBXML_VERSION < 20912) die('skip For libxml2 >= 2.9.12 only'); --FILE-- loadHTML("

foo\0bar

"); +$doc->loadHTML("

foo\0bar

", LIBXML_NOERROR); $html = $doc->saveHTML(); var_dump(strpos($html, '

foo

') !== false); file_put_contents(__DIR__ . '/80268.html', "

foo\0bar

"); $doc = new DOMDocument; -$doc->loadHTMLFile(__DIR__ . '/80268.html'); +$doc->loadHTMLFile(__DIR__ . '/80268.html', LIBXML_NOERROR); $html = $doc->saveHTML(); var_dump(strpos($html, '

foo

') !== false); ?> @@ -24,8 +24,5 @@ var_dump(strpos($html, '

foo

') !== false); unlink(__DIR__ . '/80268.html'); ?> --EXPECTF-- -Warning: DOMDocument::loadHTML(): Char 0x0 out of allowed range in Entity, line: 1 in %s on line %d bool(false) - -Warning: DOMDocument::loadHTMLFile(): Char 0x0 out of allowed range in %s on line %d bool(false) diff --git a/ext/dom/tests/gh16535.phpt b/ext/dom/tests/gh16535.phpt index 1c8d282303c88..adb1dfa91f204 100644 --- a/ext/dom/tests/gh16535.phpt +++ b/ext/dom/tests/gh16535.phpt @@ -14,7 +14,7 @@ try { } catch (DOMException $e) { echo $e->getMessage(), "\n"; } -$v2->loadHTML("oU"); +$v2->loadHTML("

oU

"); echo $v2->saveXML(); ?> diff --git a/ext/dom/tests/gh17847.phpt b/ext/dom/tests/gh17847.phpt index c32263bfe240f..b2c4caff2fc75 100644 --- a/ext/dom/tests/gh17847.phpt +++ b/ext/dom/tests/gh17847.phpt @@ -13,7 +13,7 @@ $doc->loadXML(<< -

garbage

+

garbage

@@ -22,20 +22,31 @@ XML); $xpath = new DOMXPath($doc); $garbage = []; -foreach ($xpath->query('//p') as $entry) +foreach ($xpath->query('//p') as $entry) { $garbage[] = $entry; + foreach ($entry->attributes as $attr) { + $garbage[] = $attr; + foreach ($attr->childNodes as $child) { + $garbage[] = $child; + } + } +} @$doc->xinclude(); foreach ($garbage as $node) { - try { - var_dump($node->localName); - } catch (DOMException $e) { - echo $e->getMessage(), "\n"; - } + try { + var_dump($node->localName); + } catch (DOMException $e) { + echo $e->getMessage(), "\n"; + } } ?> --EXPECT-- Invalid State Error Invalid State Error Invalid State Error +Invalid State Error +Invalid State Error +Invalid State Error +Invalid State Error diff --git a/ext/dom/tests/gh17991.phpt b/ext/dom/tests/gh17991.phpt new file mode 100644 index 0000000000000..4fc2c5b4ec1eb --- /dev/null +++ b/ext/dom/tests/gh17991.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-17991 (Assertion failure dom_attr_value_write) +--EXTENSIONS-- +dom +--FILE-- +value = new Test); +} +$box = new Box(); +test($box); +test($attr); +?> +--EXPECTF-- +object(Test)#%d (0) { +} + +Fatal error: Uncaught TypeError: Cannot assign Test to property DOMAttr::$value of type string in %s:%d +Stack trace: +#0 %s(%d): test(Object(DOMAttr)) +#1 {main} + thrown in %s on line %d diff --git a/ext/dom/tests/gh18304.phpt b/ext/dom/tests/gh18304.phpt new file mode 100644 index 0000000000000..ead44306ff801 --- /dev/null +++ b/ext/dom/tests/gh18304.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault) +--CREDITS-- +orose-assetgo +--EXTENSIONS-- +dom +--FILE-- +$field .= 'hello'; +var_dump($text->$field); +?> +--EXPECT-- +string(5) "hello" diff --git a/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_001.phpt b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_001.phpt new file mode 100644 index 0000000000000..47212cb34100a --- /dev/null +++ b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_001.phpt @@ -0,0 +1,60 @@ +--TEST-- +GHSA-p3x9-6h7p-cgfc: libxml streams use wrong `content-type` header when requesting a redirected resource (Basic) +--EXTENSIONS-- +dom +--SKIPIF-- + +--FILE-- + + + + GHSA-p3x9-6h7p-cgfc + + + + + + +

GHSA-p3x9-6h7p-cgfc

+ + + EOT; + // Intentionally using non-standard casing for content-type to verify it is matched not case sensitively. + yield "data://text/plain,HTTP/1.1 200 OK\r\nconteNt-tyPe: text/html; charset=utf-8\r\n\r\n{$xml}"; +} + +['pid' => $pid, 'uri' => $uri] = http_server('genResponses', $output); +$document = new \DOMDocument(); +$document->loadHTMLFile($uri); + +$h1 = $document->getElementsByTagName('h1'); +var_dump($h1->length); +var_dump($document->saveHTML()); +http_server_kill($pid); +?> +--EXPECT-- +int(1) +string(266) " + + + GHSA-p3x9-6h7p-cgfc + + + + + + +

GHSA-p3x9-6h7p-cgfc

+ + +" diff --git a/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_002.phpt b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_002.phpt new file mode 100644 index 0000000000000..a7eff3b9a8b76 --- /dev/null +++ b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_002.phpt @@ -0,0 +1,60 @@ +--TEST-- +GHSA-p3x9-6h7p-cgfc: libxml streams use wrong `content-type` header when requesting a redirected resource (Missing content-type) +--EXTENSIONS-- +dom +--SKIPIF-- + +--FILE-- + + + + GHSA-p3x9-6h7p-cgfc + + + + + + +

GHSA-p3x9-6h7p-cgfc

+ + + EOT; + // Missing content-type in actual response. + yield "data://text/plain,HTTP/1.1 200 OK\r\n\r\n{$xml}"; +} + +['pid' => $pid, 'uri' => $uri] = http_server('genResponses', $output); +$document = new \DOMDocument(); +$document->loadHTMLFile($uri); + +$h1 = $document->getElementsByTagName('h1'); +var_dump($h1->length); +var_dump($document->saveHTML()); +http_server_kill($pid); +?> +--EXPECT-- +int(1) +string(266) " + + + GHSA-p3x9-6h7p-cgfc + + + + + + +

GHSA-p3x9-6h7p-cgfc

+ + +" diff --git a/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_003.phpt b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_003.phpt new file mode 100644 index 0000000000000..178b35f3525a5 --- /dev/null +++ b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_003.phpt @@ -0,0 +1,60 @@ +--TEST-- +GHSA-p3x9-6h7p-cgfc: libxml streams use wrong `content-type` header when requesting a redirected resource (Reason with colon) +--EXTENSIONS-- +dom +--SKIPIF-- + +--FILE-- + + + + GHSA-p3x9-6h7p-cgfc + + + + + + +

GHSA-p3x9-6h7p-cgfc

+ + + EOT; + // Missing content-type in actual response. + yield "data://text/plain,HTTP/1.1 200 OK: This is fine\r\n\r\n{$xml}"; +} + +['pid' => $pid, 'uri' => $uri] = http_server('genResponses', $output); +$document = new \DOMDocument(); +$document->loadHTMLFile($uri); + +$h1 = $document->getElementsByTagName('h1'); +var_dump($h1->length); +var_dump($document->saveHTML()); +http_server_kill($pid); +?> +--EXPECT-- +int(1) +string(266) " + + + GHSA-p3x9-6h7p-cgfc + + + + + + +

GHSA-p3x9-6h7p-cgfc

+ + +" diff --git a/ext/dom/tests/modern/common/unpacking_foreach.phpt b/ext/dom/tests/modern/common/unpacking_foreach.phpt new file mode 100644 index 0000000000000..b2bb301ccdc11 --- /dev/null +++ b/ext/dom/tests/modern/common/unpacking_foreach.phpt @@ -0,0 +1,30 @@ +--TEST-- +unpacking vs foreach in new DOM +--EXTENSIONS-- +dom +--FILE-- +Hi

hi

", + options: LIBXML_NOERROR, +); + +foreach ($html->body->childNodes as $node) { + echo $node->localName, "\n"; +} + +echo "---\n"; + +foreach ([...$html->body->childNodes] as $node) { + echo $node->localName, "\n"; +} + +?> +--EXPECT-- +h1 +p +--- +h1 +p diff --git a/ext/dom/tests/modern/html/parser/gh18090.phpt b/ext/dom/tests/modern/html/parser/gh18090.phpt new file mode 100644 index 0000000000000..c32f5ddb51336 --- /dev/null +++ b/ext/dom/tests/modern/html/parser/gh18090.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-18090 (Svg attributes and tag names are being lowercased) +--EXTENSIONS-- +dom +--FILE-- +', LIBXML_NOERROR)->saveHTML(), "\n"; + +echo \Dom\HTMLDocument::createFromString('', LIBXML_NOERROR)->saveHTML(), "\n"; + +echo \Dom\HTMLDocument::createFromString('', LIBXML_NOERROR)->querySelector('svg')->attributes[0]->name, "\n"; +?> +--EXPECT-- + + +viewBox diff --git a/ext/dom/tests/modern/html/parser/predefined_namespaces.phpt b/ext/dom/tests/modern/html/parser/predefined_namespaces.phpt index 7e78460454e60..b4c07c6fb3bb8 100644 --- a/ext/dom/tests/modern/html/parser/predefined_namespaces.phpt +++ b/ext/dom/tests/modern/html/parser/predefined_namespaces.phpt @@ -47,7 +47,7 @@ echo $dom->saveXml(); svg http://www.w3.org/2000/svg Attribute: width (NONE) Attribute: height (NONE) - Attribute: viewbox (NONE) + Attribute: viewBox (NONE) rect http://www.w3.org/2000/svg Attribute: id (NONE) Attribute: x (NONE) @@ -65,7 +65,7 @@ svg http://www.w3.org/1998/Math/MathML Test - + @@ -85,7 +85,7 @@ svg http://www.w3.org/1998/Math/MathML Test - + diff --git a/ext/dom/tests/unpack_foreach_behaviour.phpt b/ext/dom/tests/unpack_foreach_behaviour.phpt new file mode 100644 index 0000000000000..42fe896d9f786 --- /dev/null +++ b/ext/dom/tests/unpack_foreach_behaviour.phpt @@ -0,0 +1,31 @@ +--TEST-- +Unpacking vs foreach behaviour +--EXTENSIONS-- +dom +--FILE-- +loadXML(''); + +echo "--- By foreach: ---\n"; + +foreach ($dom->documentElement->getElementsByTagName('*') as $node) { + var_dump($node->localName); +} + +echo "--- By unpacking: ---\n"; + +$iter = $dom->documentElement->getElementsByTagName('*'); +foreach ([...$iter] as $node) { + var_dump($node->localName); +} + +?> +--EXPECT-- +--- By foreach: --- +string(1) "a" +string(1) "b" +--- By unpacking: --- +string(1) "a" +string(1) "b" diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c index c6f8053d1a3bf..8707af1fa94cf 100644 --- a/ext/dom/xpath.c +++ b/ext/dom/xpath.c @@ -499,14 +499,14 @@ PHP_METHOD(DOMXPath, quote) { memcpy(ZSTR_VAL(output) + 1, input, input_len); ZSTR_VAL(output)[input_len + 1] = '\''; ZSTR_VAL(output)[input_len + 2] = '\0'; - RETURN_STR(output); + RETURN_NEW_STR(output); } else if (memchr(input, '"', input_len) == NULL) { zend_string *const output = zend_string_safe_alloc(1, input_len, 2, false); ZSTR_VAL(output)[0] = '"'; memcpy(ZSTR_VAL(output) + 1, input, input_len); ZSTR_VAL(output)[input_len + 1] = '"'; ZSTR_VAL(output)[input_len + 2] = '\0'; - RETURN_STR(output); + RETURN_NEW_STR(output); } else { smart_str output = {0}; // need to use the concat() trick published by Robert Rossney at https://stackoverflow.com/a/1352556/1067003 @@ -527,8 +527,8 @@ PHP_METHOD(DOMXPath, quote) { smart_str_appendc(&output, ','); } ZEND_ASSERT(ptr == end); - ZSTR_VAL(output.s)[output.s->len - 1] = ')'; - RETURN_STR(smart_str_extract(&output)); + ZSTR_VAL(output.s)[ZSTR_LEN(output.s) - 1] = ')'; + RETURN_NEW_STR(smart_str_extract(&output)); } } /* }}} */ diff --git a/ext/enchant/enchant.c b/ext/enchant/enchant.c index bcea06a83d7ad..d1d9ee60c440a 100644 --- a/ext/enchant/enchant.c +++ b/ext/enchant/enchant.c @@ -113,9 +113,9 @@ enumerate_providers_fn (const char * const name, array_init(&tmp_array); - add_assoc_string(&tmp_array, "name", (char *)name); - add_assoc_string(&tmp_array, "desc", (char *)desc); - add_assoc_string(&tmp_array, "file", (char *)file); + add_assoc_string(&tmp_array, "name", name); + add_assoc_string(&tmp_array, "desc", desc); + add_assoc_string(&tmp_array, "file", file); add_next_index_zval(zdesc, &tmp_array); } /* }}} */ @@ -129,10 +129,10 @@ describe_dict_fn (const char * const lang, { zval *zdesc = (zval *) ud; array_init(zdesc); - add_assoc_string(zdesc, "lang", (char *)lang); - add_assoc_string(zdesc, "name", (char *)name); - add_assoc_string(zdesc, "desc", (char *)desc); - add_assoc_string(zdesc, "file", (char *)file); + add_assoc_string(zdesc, "lang", lang); + add_assoc_string(zdesc, "name", name); + add_assoc_string(zdesc, "desc", desc); + add_assoc_string(zdesc, "file", file); } /* }}} */ @@ -144,10 +144,10 @@ static void php_enchant_list_dicts_fn( const char * const lang_tag, zval tmp_array; array_init(&tmp_array); - add_assoc_string(&tmp_array, "lang_tag", (char *)lang_tag); - add_assoc_string(&tmp_array, "provider_name", (char *)provider_name); - add_assoc_string(&tmp_array, "provider_desc", (char *)provider_desc); - add_assoc_string(&tmp_array, "provider_file", (char *)provider_file); + add_assoc_string(&tmp_array, "lang_tag", lang_tag); + add_assoc_string(&tmp_array, "provider_name", provider_name); + add_assoc_string(&tmp_array, "provider_desc", provider_desc); + add_assoc_string(&tmp_array, "provider_file", provider_file); add_next_index_zval(zdesc, &tmp_array); } @@ -318,7 +318,7 @@ PHP_FUNCTION(enchant_broker_get_error) msg = enchant_broker_get_error(pbroker->pbroker); if (msg) { - RETURN_STRING((char *)msg); + RETURN_STRING(msg); } RETURN_FALSE; } @@ -346,12 +346,12 @@ PHP_FUNCTION(enchant_broker_set_dict_path) switch (dict_type) { case PHP_ENCHANT_MYSPELL: - enchant_broker_set_param(pbroker->pbroker, "enchant.myspell.dictionary.path", (const char *)value); + enchant_broker_set_param(pbroker->pbroker, "enchant.myspell.dictionary.path", value); RETURN_TRUE; break; case PHP_ENCHANT_ISPELL: - enchant_broker_set_param(pbroker->pbroker, "enchant.ispell.dictionary.path", (const char *)value); + enchant_broker_set_param(pbroker->pbroker, "enchant.ispell.dictionary.path", value); RETURN_TRUE; break; @@ -440,7 +440,7 @@ PHP_FUNCTION(enchant_broker_request_dict) RETURN_THROWS(); } - pdict = enchant_broker_request_dict(pbroker->pbroker, (const char *)tag); + pdict = enchant_broker_request_dict(pbroker->pbroker, tag); if (pdict) { pbroker->nb_dict++; diff --git a/ext/exif/exif.c b/ext/exif/exif.c index 859324b1b96f5..9169861728869 100644 --- a/ext/exif/exif.c +++ b/ext/exif/exif.c @@ -420,6 +420,9 @@ static char *exif_get_tagformat(int format) #define TAG_EXIFVERSION 0x9000 #define TAG_DATE_TIME_ORIGINAL 0x9003 #define TAG_DATE_TIME_DIGITIZED 0x9004 +#define TAG_OFFSET_TIME 0x9010 +#define TAG_OFFSET_TIME_ORIGINAL 0x9011 +#define TAG_OFFSET_TIME_DIGITIZED 0x9012 #define TAG_COMPONENT_CONFIG 0x9101 #define TAG_COMPRESSED_BITS_PER_PIXEL 0x9102 #define TAG_SHUTTERSPEED 0x9201 @@ -692,6 +695,9 @@ static tag_info_array tag_table_IFD = { { 0x9000, "ExifVersion"}, { 0x9003, "DateTimeOriginal"}, { 0x9004, "DateTimeDigitized"}, + { 0x9010, "OffsetTime"}, + { 0x9011, "OffsetTimeOriginal"}, + { 0x9012, "OffsetTimeDigitized"}, { 0x9101, "ComponentsConfiguration"}, { 0x9102, "CompressedBitsPerPixel"}, { 0x9201, "ShutterSpeedValue"}, @@ -1833,7 +1839,7 @@ typedef struct { #define FOUND_WINXP (1<= and <= to do the checks, respectively. */ - end = start + length; + const char *end = start + length; return start >= info->valid_start && end <= info->valid_end; } @@ -2157,18 +2162,15 @@ static int exif_file_sections_realloc(image_info_type *ImageInfo, int section_in /* {{{ exif_file_section_free Discard all file_sections in ImageInfo */ -static bool exif_file_sections_free(image_info_type *ImageInfo) +static void exif_file_sections_free(image_info_type *ImageInfo) { - int i; - if (ImageInfo->file.count) { - for (i=0; ifile.count; i++) { + for (int i = 0; ifile.count; i++) { EFREE_IF(ImageInfo->file.list[i].data); } } EFREE_IF(ImageInfo->file.list); ImageInfo->file.count = 0; - return true; } /* }}} */ @@ -2185,7 +2187,7 @@ static image_info_data *exif_alloc_image_info_data(image_info_list *info_list) { /* {{{ exif_iif_add_value Add a value to image_info */ -static void exif_iif_add_value(image_info_type *image_info, int section_index, char *name, int tag, int format, size_t length, void* value, size_t value_len, int motorola_intel) +static void exif_iif_add_value(image_info_type *image_info, int section_index, const char *name, int tag, int format, size_t length, void* value, size_t value_len, int motorola_intel) { size_t idex; void *vptr, *vptr_end; @@ -2324,7 +2326,7 @@ static void exif_iif_add_value(image_info_type *image_info, int section_index, c /* {{{ exif_iif_add_tag Add a tag from IFD to image_info */ -static void exif_iif_add_tag(image_info_type *image_info, int section_index, char *name, int tag, int format, size_t length, void* value, size_t value_len) +static void exif_iif_add_tag(image_info_type *image_info, int section_index, const char *name, int tag, int format, size_t length, void* value, size_t value_len) { exif_iif_add_value(image_info, section_index, name, tag, format, length, value, value_len, image_info->motorola_intel); } @@ -2333,7 +2335,7 @@ static void exif_iif_add_tag(image_info_type *image_info, int section_index, cha /* {{{ exif_iif_add_int Add an int value to image_info */ -static void exif_iif_add_int(image_info_type *image_info, int section_index, char *name, int value) +static void exif_iif_add_int(image_info_type *image_info, int section_index, const char *name, int value) { image_info_data *info_data = exif_alloc_image_info_data(&image_info->info_list[section_index]); info_data->tag = TAG_NONE; @@ -2348,7 +2350,7 @@ static void exif_iif_add_int(image_info_type *image_info, int section_index, cha /* {{{ exif_iif_add_str Add a string value to image_info MUST BE NUL TERMINATED */ -static void exif_iif_add_str(image_info_type *image_info, int section_index, char *name, char *value) +static void exif_iif_add_str(image_info_type *image_info, int section_index, const char *name, const char *value) { if (value) { image_info_data *info_data = @@ -2366,7 +2368,7 @@ static void exif_iif_add_str(image_info_type *image_info, int section_index, cha /* {{{ exif_iif_add_fmt Add a format string value to image_info MUST BE NUL TERMINATED */ -static void exif_iif_add_fmt(image_info_type *image_info, int section_index, char *name, char *value, ...) +static void exif_iif_add_fmt(image_info_type *image_info, int section_index, const char *name, char *value, ...) { char *tmp; va_list arglist; @@ -2384,7 +2386,7 @@ static void exif_iif_add_fmt(image_info_type *image_info, int section_index, cha /* {{{ exif_iif_add_str Add a string value to image_info MUST BE NUL TERMINATED */ -static void exif_iif_add_buffer(image_info_type *image_info, int section_index, char *name, int length, char *value) +static void exif_iif_add_buffer(image_info_type *image_info, int section_index, const char *name, int length, const char *value) { if (value) { image_info_data *info_data = @@ -2405,11 +2407,10 @@ static void exif_iif_add_buffer(image_info_type *image_info, int section_index, Free memory allocated for image_info */ static void exif_iif_free(image_info_type *image_info, int section_index) { - int i; void *f; /* faster */ if (image_info->info_list[section_index].count) { - for (i=0; i < image_info->info_list[section_index].count; i++) { + for (int i = 0; i < image_info->info_list[section_index].count; i++) { if ((f=image_info->info_list[section_index].list[i].name) != NULL) { efree(f); } @@ -2450,7 +2451,6 @@ static void exif_iif_free(image_info_type *image_info, int section_index) { * Add image_info to associative array value. */ static void add_assoc_image_info(zval *value, int sub_array, image_info_type *image_info, int section_index) { - char buffer[64], uname[64]; int idx = 0, unknown = 0; if (!image_info->info_list[section_index].count) { @@ -2468,6 +2468,8 @@ static void add_assoc_image_info(zval *value, int sub_array, image_info_type *im image_info_data *info_data = &image_info->info_list[section_index].list[i]; image_info_value *info_value = &info_data->value; const char *name = info_data->name; + char uname[64]; + if (!name) { snprintf(uname, sizeof(uname), "%d", unknown++); name = uname; @@ -2518,6 +2520,7 @@ static void add_assoc_image_info(zval *value, int sub_array, image_info_type *im array_init(&array); } for (int ap = 0; ap < l; ap++) { + char buffer[64]; if (l>1) { info_value = &info_data->value.list[ap]; } @@ -2787,8 +2790,7 @@ PHP_FUNCTION(exif_tagname) * Create a value for an ifd from an info_data pointer */ static void* exif_ifd_make_value(image_info_data *info_data, int motorola_intel) { size_t byte_count; - char *value_ptr, *data_ptr; - size_t i; + char *value_ptr; image_info_value *info_value; @@ -2810,8 +2812,8 @@ static void* exif_ifd_make_value(image_info_data *info_data, int motorola_intel) *value_ptr = info_data->value.i; return value_ptr; } else { - data_ptr = value_ptr; - for(i=0; ilength; i++) { + char *data_ptr = value_ptr; + for(size_t i = 0; i < info_data->length; i++) { if (info_data->length==1) { info_value = &info_data->value; } else { @@ -2980,7 +2982,7 @@ static void exif_thumbnail_extract(image_info_type *ImageInfo, const exif_offset /* {{{ exif_process_undefined * Copy a string/buffer in Exif header to a character string and return length of allocated buffer if any. */ -static int exif_process_undefined(char **result, char *value, size_t byte_count) { +static int exif_process_undefined(char **result, const char *value, size_t byte_count) { /* we cannot use strlcpy - here the problem is that we have to copy NUL * chars up to byte_count, we also have to add a single NUL character to * force end of string. @@ -2996,7 +2998,7 @@ static int exif_process_undefined(char **result, char *value, size_t byte_count) /* {{{ exif_process_string_raw * Copy a string in Exif header to a character string returns length of allocated buffer if any. */ -static int exif_process_string_raw(char **result, char *value, size_t byte_count) { +static int exif_process_string_raw(char **result, const char *value, size_t byte_count) { /* we cannot use strlcpy - here the problem is that we have to copy NUL * chars up to byte_count, we also have to add a single NUL character to * force end of string. @@ -3014,7 +3016,7 @@ static int exif_process_string_raw(char **result, char *value, size_t byte_count /* {{{ exif_process_string * Copy a string in Exif header to a character string and return length of allocated buffer if any. * In contrast to exif_process_string this function does always return a string buffer */ -static int exif_process_string(char **result, char *value, size_t byte_count) { +static int exif_process_string(char **result, const char *value, size_t byte_count) { /* we cannot use strlcpy - here the problem is that we cannot use strlen to * determine length of string and we cannot use strlcpy with len=byte_count+1 * because then we might get into an EXCEPTION if we exceed an allocated @@ -3032,10 +3034,8 @@ static int exif_process_string(char **result, char *value, size_t byte_count) { /* {{{ exif_process_user_comment * Process UserComment in IFD. */ -static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoPtr, char **pszEncoding, char *szValuePtr, int ByteCount) +static int exif_process_user_comment(const image_info_type *ImageInfo, char **pszInfoPtr, char **pszEncoding, char *szValuePtr, int ByteCount) { - int a; - char *decode; size_t len; *pszEncoding = NULL; @@ -3043,7 +3043,8 @@ static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoP if (ByteCount>=8) { const zend_encoding *from, *to; if (!memcmp(szValuePtr, "UNICODE\0", 8)) { - *pszEncoding = estrdup((const char*)szValuePtr); + char *decode; + *pszEncoding = estrdup(szValuePtr); szValuePtr = szValuePtr+8; ByteCount -= 8; /* First try to detect BOM: ZERO WIDTH NOBREAK SPACE (FEFF 16) @@ -3076,12 +3077,12 @@ static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoP } return len; } else if (!memcmp(szValuePtr, "ASCII\0\0\0", 8)) { - *pszEncoding = estrdup((const char*)szValuePtr); + *pszEncoding = estrdup(szValuePtr); szValuePtr = szValuePtr+8; ByteCount -= 8; } else if (!memcmp(szValuePtr, "JIS\0\0\0\0\0", 8)) { /* JIS should be translated to MB or we leave it to the user - leave it to the user */ - *pszEncoding = estrdup((const char*)szValuePtr); + *pszEncoding = estrdup(szValuePtr); szValuePtr = szValuePtr+8; ByteCount -= 8; /* XXX this will fail again if encoding_converter returns on error something different than SIZE_MAX */ @@ -3107,7 +3108,7 @@ static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoP /* Olympus has this padded with trailing spaces. Remove these first. */ if (ByteCount>0) { - for (a=ByteCount-1;a && szValuePtr[a]==' ';a--) { + for (int a = ByteCount-1; a && szValuePtr[a]==' '; a--) { (szValuePtr)[a] = '\0'; } } @@ -3120,7 +3121,7 @@ static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoP /* {{{ exif_process_unicode * Process unicode field in IFD. */ -static int exif_process_unicode(image_info_type *ImageInfo, xp_field_type *xp_field, int tag, char *szValuePtr, int ByteCount) +static int exif_process_unicode(const image_info_type *ImageInfo, xp_field_type *xp_field, int tag, const char *szValuePtr, int ByteCount) { xp_field->tag = tag; xp_field->value = NULL; @@ -3128,7 +3129,7 @@ static int exif_process_unicode(image_info_type *ImageInfo, xp_field_type *xp_fi if (zend_multibyte_encoding_converter( (unsigned char**)&xp_field->value, &xp_field->size, - (unsigned char*)szValuePtr, + (const unsigned char*)szValuePtr, ByteCount, zend_multibyte_fetch_encoding(ImageInfo->encode_unicode), zend_multibyte_fetch_encoding(ImageInfo->motorola_intel ? ImageInfo->decode_unicode_be : ImageInfo->decode_unicode_le) @@ -3143,14 +3144,13 @@ static int exif_process_unicode(image_info_type *ImageInfo, xp_field_type *xp_fi * Process nested IFDs directories in Maker Note. */ static bool exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * value_ptr, int value_len, const exif_offset_info *info, size_t displacement) { - size_t i; - int de, section_index = SECTION_MAKERNOTE; + int section_index = SECTION_MAKERNOTE; int NumDirEntries, old_motorola_intel; const maker_note_type *maker_note; char *dir_start; exif_offset_info new_info; - for (i=0; i<=sizeof(maker_note_array)/sizeof(maker_note_type); i++) { + for (size_t i = 0; i <= sizeof(maker_note_array)/sizeof(maker_note_type); i++) { if (i==sizeof(maker_note_array)/sizeof(maker_note_type)) { #ifdef EXIF_DEBUG exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "No maker note data found. Detected maker: %s (length = %d)", ImageInfo->make, ImageInfo->make ? strlen(ImageInfo->make) : 0); @@ -3231,7 +3231,7 @@ static bool exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * val break; } - for (de=0;detag_table)) { @@ -3259,16 +3259,10 @@ static bool exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * val * Process one of the nested IFDs directories. */ static bool exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entry, const exif_offset_info *info, size_t displacement, int section_index, int ReadNextIFD, tag_table_type tag_table) { - size_t length; unsigned int tag, format, components; char *value_ptr, tagname[64], cbuf[32], *outside=NULL; - size_t byte_count, offset_val, fpos, fgot; + size_t byte_count, offset_val; int64_t byte_count_signed; - xp_field_type *tmp_xp; -#ifdef EXIF_DEBUG - char *dump_data; - int dump_free; -#endif /* EXIF_DEBUG */ tag = php_ifd_get16u(dir_entry, ImageInfo->motorola_intel); format = php_ifd_get16u(dir_entry+2, ImageInfo->motorola_intel); @@ -3316,9 +3310,9 @@ static bool exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entr value_ptr = cbuf; } - fpos = php_stream_tell(ImageInfo->infile); + size_t fpos = php_stream_tell(ImageInfo->infile); php_stream_seek(ImageInfo->infile, displacement+offset_val, SEEK_SET); - fgot = php_stream_tell(ImageInfo->infile); + size_t fgot = php_stream_tell(ImageInfo->infile); if (fgot!=displacement+offset_val) { EFREE_IF(outside); exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Wrong file pointer: 0x%08X != 0x%08X", fgot, displacement+offset_val); @@ -3341,7 +3335,8 @@ static bool exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entr ImageInfo->sections_found |= FOUND_ANY_TAG; #ifdef EXIF_DEBUG - dump_data = exif_dump_data(&dump_free, format, components, ImageInfo->motorola_intel, value_ptr); + int dump_free; + char *dump_data = exif_dump_data(&dump_free, format, components, ImageInfo->motorola_intel, value_ptr); exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Process tag(x%04X=%s,@0x%04X + x%04X(=%d)): %s%s %s", tag, exif_get_tagname_debug(tag, tag_table), offset_val+displacement, byte_count, byte_count, (components>1)&&format!=TAG_FMT_UNDEFINED&&format!=TAG_FMT_STRING?"ARRAY OF ":"", exif_get_tagformat(format), dump_data); @@ -3394,7 +3389,8 @@ static bool exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entr } else { if (section_index==SECTION_IFD0 || section_index==SECTION_EXIF) switch(tag) { - case TAG_COPYRIGHT: + case TAG_COPYRIGHT: { + size_t length; /* check for " NUL NUL" */ if (byte_count>1 && (length=zend_strnlen(value_ptr, byte_count)) > 0) { if (lengthUserComment); @@ -3427,13 +3424,14 @@ static bool exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entr case TAG_XP_COMMENTS: case TAG_XP_AUTHOR: case TAG_XP_KEYWORDS: - case TAG_XP_SUBJECT: - tmp_xp = (xp_field_type*)safe_erealloc(ImageInfo->xp_fields.list, (ImageInfo->xp_fields.count+1), sizeof(xp_field_type), 0); + case TAG_XP_SUBJECT: { + xp_field_type *tmp_xp = (xp_field_type*)safe_erealloc(ImageInfo->xp_fields.list, (ImageInfo->xp_fields.count+1), sizeof(xp_field_type), 0); ImageInfo->sections_found |= FOUND_WINXP; ImageInfo->xp_fields.list = tmp_xp; ImageInfo->xp_fields.count++; exif_process_unicode(ImageInfo, &(ImageInfo->xp_fields.list[ImageInfo->xp_fields.count-1]), tag, value_ptr, byte_count); break; + } case TAG_FNUMBER: /* Simplest way of expressing aperture, so I trust it the most. @@ -4034,7 +4032,7 @@ static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir { int i, sn, num_entries, sub_section_index = 0; unsigned char *dir_entry; - size_t ifd_size, dir_size, entry_offset, next_offset, entry_length, entry_value=0, fgot; + size_t ifd_size, dir_size, next_offset, entry_length, entry_value=0; int entry_tag , entry_type; tag_table_type tag_table = exif_get_tag_table(section_index); @@ -4121,7 +4119,7 @@ static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir break; } } else { - entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel); + size_t entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel); /* if entry needs expanding ifd cache and entry is at end of current ifd cache. */ /* otherwise there may be huge holes between two entries */ if (entry_offset + entry_length > dir_offset + ifd_size @@ -4180,7 +4178,7 @@ static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir sub_section_index = SECTION_THUMBNAIL; break; } - entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel); + size_t entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel); #ifdef EXIF_DEBUG exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Next IFD: %s @0x%04X", exif_get_sectionname(sub_section_index), entry_offset); #endif @@ -4197,7 +4195,7 @@ static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir if (!ImageInfo->Thumbnail.data) { ImageInfo->Thumbnail.data = safe_emalloc(ImageInfo->Thumbnail.size, 1, 0); php_stream_seek(ImageInfo->infile, ImageInfo->Thumbnail.offset, SEEK_SET); - fgot = exif_read_from_stream_file_looped(ImageInfo->infile, ImageInfo->Thumbnail.data, ImageInfo->Thumbnail.size); + size_t fgot = exif_read_from_stream_file_looped(ImageInfo->infile, ImageInfo->Thumbnail.data, ImageInfo->Thumbnail.size); if (fgot != ImageInfo->Thumbnail.size) { EXIF_ERRLOG_THUMBEOF(ImageInfo) efree(ImageInfo->Thumbnail.data); @@ -4237,7 +4235,7 @@ static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir if (!ImageInfo->Thumbnail.data && ImageInfo->Thumbnail.offset && ImageInfo->Thumbnail.size && ImageInfo->read_thumbnail) { ImageInfo->Thumbnail.data = safe_emalloc(ImageInfo->Thumbnail.size, 1, 0); php_stream_seek(ImageInfo->infile, ImageInfo->Thumbnail.offset, SEEK_SET); - fgot = exif_read_from_stream_file_looped(ImageInfo->infile, ImageInfo->Thumbnail.data, ImageInfo->Thumbnail.size); + size_t fgot = exif_read_from_stream_file_looped(ImageInfo->infile, ImageInfo->Thumbnail.data, ImageInfo->Thumbnail.size); if (fgot != ImageInfo->Thumbnail.size) { EXIF_ERRLOG_THUMBEOF(ImageInfo) efree(ImageInfo->Thumbnail.data); @@ -4286,70 +4284,79 @@ static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offs static bool exif_scan_FILE_header(image_info_type *ImageInfo) { unsigned char file_header[8]; - bool ret = false; ImageInfo->FileType = IMAGE_FILETYPE_UNKNOWN; - if (ImageInfo->FileSize >= 2) { - php_stream_seek(ImageInfo->infile, 0, SEEK_SET); - if (exif_read_from_stream_file_looped(ImageInfo->infile, (char*)file_header, 2) != 2) { + if (UNEXPECTED(ImageInfo->FileSize < 2)) { + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "File too small (%d)", ImageInfo->FileSize); + return false; + } + + php_stream_seek(ImageInfo->infile, 0, SEEK_SET); + if (exif_read_from_stream_file_looped(ImageInfo->infile, (char*)file_header, 2) != 2) { + return false; + } + + if ((file_header[0]==0xff) && (file_header[1]==M_SOI)) { + ImageInfo->FileType = IMAGE_FILETYPE_JPEG; + if (exif_scan_JPEG_header(ImageInfo)) { + return true; + } else { + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid JPEG file"); + return false; + } + } else if (ImageInfo->FileSize >= 8) { + if (exif_read_from_stream_file_looped(ImageInfo->infile, (char*)(file_header+2), 6) != 6) { return false; } - if ((file_header[0]==0xff) && (file_header[1]==M_SOI)) { - ImageInfo->FileType = IMAGE_FILETYPE_JPEG; - if (exif_scan_JPEG_header(ImageInfo)) { - ret = true; + + if (!memcmp(file_header, "II\x2A\x00", 4)) { + ImageInfo->FileType = IMAGE_FILETYPE_TIFF_II; + ImageInfo->motorola_intel = 0; +#ifdef EXIF_DEBUG + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "File has TIFF/II format"); +#endif + ImageInfo->sections_found |= FOUND_IFD0; + if (exif_process_IFD_in_TIFF( + ImageInfo, + php_ifd_get32u(file_header + 4, ImageInfo->motorola_intel), + SECTION_IFD0 + )) { + return true; } else { - exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid JPEG file"); - } - } else if (ImageInfo->FileSize >= 8) { - if (exif_read_from_stream_file_looped(ImageInfo->infile, (char*)(file_header+2), 6) != 6) { + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid TIFF file"); return false; } - if (!memcmp(file_header, "II\x2A\x00", 4)) { - ImageInfo->FileType = IMAGE_FILETYPE_TIFF_II; - ImageInfo->motorola_intel = 0; -#ifdef EXIF_DEBUG - exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "File has TIFF/II format"); -#endif - ImageInfo->sections_found |= FOUND_IFD0; - if (exif_process_IFD_in_TIFF(ImageInfo, - php_ifd_get32u(file_header + 4, ImageInfo->motorola_intel), - SECTION_IFD0)) { - ret = true; - } else { - exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid TIFF file"); - } - } else if (!memcmp(file_header, "MM\x00\x2a", 4)) { - ImageInfo->FileType = IMAGE_FILETYPE_TIFF_MM; - ImageInfo->motorola_intel = 1; + } else if (!memcmp(file_header, "MM\x00\x2a", 4)) { + ImageInfo->FileType = IMAGE_FILETYPE_TIFF_MM; + ImageInfo->motorola_intel = 1; #ifdef EXIF_DEBUG - exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "File has TIFF/MM format"); + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "File has TIFF/MM format"); #endif - ImageInfo->sections_found |= FOUND_IFD0; - if (exif_process_IFD_in_TIFF(ImageInfo, - php_ifd_get32u(file_header + 4, ImageInfo->motorola_intel), - SECTION_IFD0)) { - ret = true; - } else { - exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid TIFF file"); - } + ImageInfo->sections_found |= FOUND_IFD0; + if (exif_process_IFD_in_TIFF( + ImageInfo, + php_ifd_get32u(file_header + 4, ImageInfo->motorola_intel), + SECTION_IFD0 + )) { + return true; } else { - exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "File not supported"); + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid TIFF file"); return false; } + } else { + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "File not supported"); + return false; } - } else { - exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "File too small (%d)", ImageInfo->FileSize); } - return ret; + return false; } /* }}} */ /* {{{ exif_discard_imageinfo Discard data scanned by exif_read_file. */ -static bool exif_discard_imageinfo(image_info_type *ImageInfo) +static void exif_discard_imageinfo(image_info_type *ImageInfo) { int i; @@ -4377,7 +4384,6 @@ static bool exif_discard_imageinfo(image_info_type *ImageInfo) } exif_file_sections_free(ImageInfo); memset(ImageInfo, 0, sizeof(*ImageInfo)); - return true; } /* }}} */ @@ -4465,7 +4471,7 @@ static bool exif_read_from_stream(image_info_type *ImageInfo, php_stream *stream /* }}} */ /* {{{ exif_read_from_file */ -static bool exif_read_from_file(image_info_type *ImageInfo, char *FileName, int read_thumbnail, int read_all) +static bool exif_read_from_file(image_info_type *ImageInfo, const char *FileName, int read_thumbnail, int read_all) { bool ret; php_stream *stream; @@ -4497,7 +4503,7 @@ PHP_FUNCTION(exif_read_data) bool ret; int i, sections_needed = 0; image_info_type ImageInfo; - char tmp[64], *sections_str, *s; + char *sections_str; /* Parse arguments */ ZEND_PARSE_PARAMETERS_START(1, 4) @@ -4513,7 +4519,7 @@ PHP_FUNCTION(exif_read_data) if (z_sections_needed) { spprintf(§ions_str, 0, ",%s,", ZSTR_VAL(z_sections_needed)); /* sections_str DOES start with , and SPACES are NOT allowed in names */ - s = sections_str; + char *s = sections_str; while (*++s) { if (*s == ' ') { *s = ','; @@ -4521,6 +4527,7 @@ PHP_FUNCTION(exif_read_data) } for (i = 0; i < SECTION_COUNT; i++) { + char tmp[64]; snprintf(tmp, sizeof(tmp), ",%s,", exif_get_sectionname(i)); if (strstr(sections_str, tmp)) { sections_needed |= 1< +--EXPECTF-- +array(17) { + ["FileName"]=> + string(12) "image028.jpg" + ["FileDateTime"]=> + int(%d) + ["FileSize"]=> + int(%d) + ["FileType"]=> + int(2) + ["MimeType"]=> + string(10) "image/jpeg" + ["SectionsFound"]=> + string(13) "ANY_TAG, IFD0" + ["COMPUTED"]=> + array(5) { + ["html"]=> + string(20) "width="1" height="1"" + ["Height"]=> + int(1) + ["Width"]=> + int(1) + ["IsColor"]=> + int(1) + ["ByteOrderMotorola"]=> + int(1) + } + ["XResolution"]=> + string(5) "300/1" + ["YResolution"]=> + string(5) "300/1" + ["ResolutionUnit"]=> + int(2) + ["DateTime"]=> + string(19) "2025:04:03 00:02:00" + ["YCbCrPositioning"]=> + int(1) + ["DateTimeOriginal"]=> + string(19) "2025:04:03 00:00:00" + ["DateTimeDigitized"]=> + string(19) "2025:04:03 00:01:00" + ["OffsetTime"]=> + string(6) "-02:00" + ["OffsetTimeOriginal"]=> + string(6) "+00:00" + ["OffsetTimeDigitized"]=> + string(6) "-01:00" +} diff --git a/ext/exif/tests/image028.jpg b/ext/exif/tests/image028.jpg new file mode 100644 index 0000000000000..57110cec8f768 Binary files /dev/null and b/ext/exif/tests/image028.jpg differ diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 3fc97577abdea..621e60c6f19a3 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -220,14 +220,14 @@ static zend_internal_function zend_ffi_type_fn; /* forward declarations */ static void _zend_ffi_type_dtor(zend_ffi_type *type); static void zend_ffi_finalize_type(zend_ffi_dcl *dcl); -static bool zend_ffi_is_same_type(zend_ffi_type *type1, zend_ffi_type *type2); +static bool zend_ffi_is_same_type(const zend_ffi_type *type1, const zend_ffi_type *type2); static zend_ffi_type *zend_ffi_remember_type(zend_ffi_type *type); static char *zend_ffi_parse_directives(const char *filename, char *code_pos, char **scope_name, char **lib, bool preload); static ZEND_FUNCTION(ffi_trampoline); static ZEND_COLD void zend_ffi_return_unsupported(zend_ffi_type *type); static ZEND_COLD void zend_ffi_pass_unsupported(zend_ffi_type *type); -static ZEND_COLD void zend_ffi_assign_incompatible(zval *arg, zend_ffi_type *type); -static bool zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *src_type); +static ZEND_COLD void zend_ffi_assign_incompatible(const zval *arg, const zend_ffi_type *type); +static bool zend_ffi_is_compatible_type(const zend_ffi_type *dst_type, const zend_ffi_type *src_type); #if FFI_CLOSURES static void *zend_ffi_create_callback(zend_ffi_type *type, zval *value); @@ -270,7 +270,7 @@ static zend_object *zend_ffi_cdata_new(zend_class_entry *class_type) /* {{{ */ } /* }}} */ -static bool zend_ffi_func_ptr_are_compatible(zend_ffi_type *dst_type, zend_ffi_type *src_type) /* {{{ */ +static bool zend_ffi_func_ptr_are_compatible(const zend_ffi_type *dst_type, const zend_ffi_type *src_type) /* {{{ */ { uint32_t dst_argc, src_argc, i; zend_ffi_type *dst_arg, *src_arg; @@ -313,7 +313,7 @@ static bool zend_ffi_func_ptr_are_compatible(zend_ffi_type *dst_type, zend_ffi_t } /* }}} */ -static bool zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *src_type) /* {{{ */ +static bool zend_ffi_is_compatible_type(const zend_ffi_type *dst_type, const zend_ffi_type *src_type) /* {{{ */ { while (1) { if (dst_type == src_type) { @@ -354,7 +354,7 @@ static bool zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type * } /* }}} */ -static ffi_type* zend_ffi_face_struct_add_fields(ffi_type* t, zend_ffi_type *type, int *i, size_t size) +static ffi_type* zend_ffi_face_struct_add_fields(ffi_type* t, const zend_ffi_type *type, int *i, size_t size) { zend_ffi_field *field; @@ -418,7 +418,7 @@ static ffi_type* zend_ffi_face_struct_add_fields(ffi_type* t, zend_ffi_type *typ return t; } -static ffi_type *zend_ffi_make_fake_struct_type(zend_ffi_type *type) /* {{{ */ +static ffi_type *zend_ffi_make_fake_struct_type(const zend_ffi_type *type) /* {{{ */ { /* for unions we use only the first field */ uint32_t num_fields = !(type->attr & ZEND_FFI_ATTR_UNION) ? @@ -438,7 +438,7 @@ static ffi_type *zend_ffi_make_fake_struct_type(zend_ffi_type *type) /* {{{ */ } /* }}} */ -static ffi_type *zend_ffi_get_type(zend_ffi_type *type) /* {{{ */ +static ffi_type *zend_ffi_get_type(const zend_ffi_type *type) /* {{{ */ { zend_ffi_type_kind kind = type->kind; @@ -633,7 +633,7 @@ static zend_always_inline void zend_ffi_cdata_to_zval(zend_ffi_cdata *cdata, voi } /* }}} */ -static uint64_t zend_ffi_bit_field_read(void *ptr, zend_ffi_field *field) /* {{{ */ +static uint64_t zend_ffi_bit_field_read(void *ptr, const zend_ffi_field *field) /* {{{ */ { size_t bit = field->first_bit; size_t last_bit = bit + field->bits - 1; @@ -675,7 +675,7 @@ static uint64_t zend_ffi_bit_field_read(void *ptr, zend_ffi_field *field) /* {{{ } /* }}} */ -static void zend_ffi_bit_field_to_zval(void *ptr, zend_ffi_field *field, zval *rv) /* {{{ */ +static void zend_ffi_bit_field_to_zval(void *ptr, const zend_ffi_field *field, zval *rv) /* {{{ */ { uint64_t val = zend_ffi_bit_field_read(ptr, field); if (ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_CHAR @@ -693,7 +693,7 @@ static void zend_ffi_bit_field_to_zval(void *ptr, zend_ffi_field *field, zval *r } /* }}} */ -static void zend_ffi_zval_to_bit_field(void *ptr, zend_ffi_field *field, zval *value) /* {{{ */ +static void zend_ffi_zval_to_bit_field(void *ptr, const zend_ffi_field *field, const zval *value) /* {{{ */ { uint64_t val = zval_get_long(value); size_t bit = field->first_bit; @@ -744,7 +744,7 @@ static zend_always_inline zend_result zend_ffi_zval_to_cdata(void *ptr, zend_ffi /* Pointer type has special handling of CData */ if (kind != ZEND_FFI_TYPE_POINTER && Z_TYPE_P(value) == IS_OBJECT && Z_OBJCE_P(value) == zend_ffi_cdata_ce) { - zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(value); + const zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(value); if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type)) && type->size == ZEND_FFI_TYPE(cdata->type)->size) { memcpy(ptr, cdata->ptr, type->size); @@ -822,7 +822,7 @@ static zend_always_inline zend_result zend_ffi_zval_to_cdata(void *ptr, zend_ffi *(void**)ptr = NULL; break; } else if (Z_TYPE_P(value) == IS_OBJECT && Z_OBJCE_P(value) == zend_ffi_cdata_ce) { - zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(value); + const zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(value); if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) { if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) { @@ -929,7 +929,7 @@ static void zend_ffi_callback_hash_dtor(zval *zv) /* {{{ */ if (callback_data->fcc.function_handler->common.fn_flags & ZEND_ACC_CLOSURE) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(callback_data->fcc.function_handler)); } - for (int i = 0; i < callback_data->arg_count; ++i) { + for (uint32_t i = 0; i < callback_data->arg_count; ++i) { if (callback_data->arg_types[i]->type == FFI_TYPE_STRUCT) { efree(callback_data->arg_types[i]); } @@ -974,9 +974,7 @@ static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, v } if (callback_data->arg_count) { - int n = 0; - - for (n = 0; n < callback_data->arg_count; n++) { + for (uint32_t n = 0; n < callback_data->arg_count; n++) { zval_ptr_dtor(&fci.params[n]); } } @@ -1172,8 +1170,8 @@ static zval *zend_ffi_cdata_set(zend_object *obj, zend_string *member, zval *val static zend_result zend_ffi_cdata_cast_object(zend_object *readobj, zval *writeobj, int type) /* {{{ */ { if (type == IS_STRING) { - zend_ffi_cdata *cdata = (zend_ffi_cdata*)readobj; - zend_ffi_type *ctype = ZEND_FFI_TYPE(cdata->type); + const zend_ffi_cdata *cdata = (zend_ffi_cdata*)readobj; + const zend_ffi_type *ctype = ZEND_FFI_TYPE(cdata->type); void *ptr = cdata->ptr; zend_ffi_type_kind kind = ctype->kind; @@ -1700,7 +1698,7 @@ static ZEND_COLD void zend_ffi_pass_unsupported(zend_ffi_type *type) /* {{{ */ } /* }}} */ -static ZEND_COLD void zend_ffi_pass_incompatible(zval *arg, zend_ffi_type *type, uint32_t n, zend_execute_data *execute_data) /* {{{ */ +static ZEND_COLD void zend_ffi_pass_incompatible(const zval *arg, const zend_ffi_type *type, uint32_t n, const zend_execute_data *execute_data) /* {{{ */ { zend_ffi_ctype_name_buf buf1, buf2; @@ -1710,7 +1708,7 @@ static ZEND_COLD void zend_ffi_pass_incompatible(zval *arg, zend_ffi_type *type, } else { *buf1.end = 0; if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) { - zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg); + const zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg); type = ZEND_FFI_TYPE(cdata->type); buf2.start = buf2.end = buf2.buf + ((MAX_TYPE_NAME_LEN * 3) / 4); @@ -1727,7 +1725,7 @@ static ZEND_COLD void zend_ffi_pass_incompatible(zval *arg, zend_ffi_type *type, } /* }}} */ -static ZEND_COLD void zend_ffi_assign_incompatible(zval *arg, zend_ffi_type *type) /* {{{ */ +static ZEND_COLD void zend_ffi_assign_incompatible(const zval *arg, const zend_ffi_type *type) /* {{{ */ { zend_ffi_ctype_name_buf buf1, buf2; @@ -1737,7 +1735,7 @@ static ZEND_COLD void zend_ffi_assign_incompatible(zval *arg, zend_ffi_type *typ } else { *buf1.end = 0; if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) { - zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg); + const zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg); type = ZEND_FFI_TYPE(cdata->type); buf2.start = buf2.end = buf2.buf + ((MAX_TYPE_NAME_LEN * 3) / 4); @@ -1770,7 +1768,7 @@ static zend_string *zend_ffi_get_class_name(zend_string *prefix, const zend_ffi_ static zend_string *zend_ffi_cdata_get_class_name(const zend_object *zobj) /* {{{ */ { - zend_ffi_cdata *cdata = (zend_ffi_cdata*)zobj; + const zend_ffi_cdata *cdata = (zend_ffi_cdata*)zobj; return zend_ffi_get_class_name(zobj->ce->name, ZEND_FFI_TYPE(cdata->type)); } @@ -1780,10 +1778,10 @@ static int zend_ffi_cdata_compare_objects(zval *o1, zval *o2) /* {{{ */ { if (Z_TYPE_P(o1) == IS_OBJECT && Z_OBJCE_P(o1) == zend_ffi_cdata_ce && Z_TYPE_P(o2) == IS_OBJECT && Z_OBJCE_P(o2) == zend_ffi_cdata_ce) { - zend_ffi_cdata *cdata1 = (zend_ffi_cdata*)Z_OBJ_P(o1); - zend_ffi_cdata *cdata2 = (zend_ffi_cdata*)Z_OBJ_P(o2); - zend_ffi_type *type1 = ZEND_FFI_TYPE(cdata1->type); - zend_ffi_type *type2 = ZEND_FFI_TYPE(cdata2->type); + const zend_ffi_cdata *cdata1 = (zend_ffi_cdata*)Z_OBJ_P(o1); + const zend_ffi_cdata *cdata2 = (zend_ffi_cdata*)Z_OBJ_P(o2); + const zend_ffi_type *type1 = ZEND_FFI_TYPE(cdata1->type); + const zend_ffi_type *type2 = ZEND_FFI_TYPE(cdata2->type); if (type1->kind == ZEND_FFI_TYPE_POINTER && type2->kind == ZEND_FFI_TYPE_POINTER) { void *ptr1 = *(void**)cdata1->ptr; @@ -1803,8 +1801,8 @@ static int zend_ffi_cdata_compare_objects(zval *o1, zval *o2) /* {{{ */ static zend_result zend_ffi_cdata_count_elements(zend_object *obj, zend_long *count) /* {{{ */ { - zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj; - zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type); + const zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj; + const zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type); if (type->kind != ZEND_FFI_TYPE_ARRAY) { zend_throw_error(zend_ffi_exception_ce, "Attempt to count() on non C array"); @@ -1892,8 +1890,8 @@ static zend_result zend_ffi_cdata_do_operation(uint8_t opcode, zval *result, zva return SUCCESS; } else if (opcode == ZEND_SUB) { if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJCE_P(op2) == zend_ffi_cdata_ce) { - zend_ffi_cdata *cdata2 = (zend_ffi_cdata*)Z_OBJ_P(op2); - zend_ffi_type *type2 = ZEND_FFI_TYPE(cdata2->type); + const zend_ffi_cdata *cdata2 = (zend_ffi_cdata*)Z_OBJ_P(op2); + const zend_ffi_type *type2 = ZEND_FFI_TYPE(cdata2->type); if (type2->kind == ZEND_FFI_TYPE_POINTER || type2->kind == ZEND_FFI_TYPE_ARRAY) { zend_ffi_type *t1, *t2; @@ -1961,9 +1959,9 @@ static void zend_ffi_cdata_it_dtor(zend_object_iterator *iter) /* {{{ */ static zend_result zend_ffi_cdata_it_valid(zend_object_iterator *it) /* {{{ */ { - zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it; - zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ(iter->it.data); - zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type); + const zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it; + const zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ(iter->it.data); + const zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type); return (iter->key >= 0 && iter->key < type->array.length) ? SUCCESS : FAILURE; } @@ -1999,7 +1997,7 @@ static zval *zend_ffi_cdata_it_get_current_data(zend_object_iterator *it) /* {{{ static void zend_ffi_cdata_it_get_current_key(zend_object_iterator *it, zval *key) /* {{{ */ { - zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it; + const zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it; ZVAL_LONG(key, iter->key); } /* }}} */ @@ -2240,7 +2238,7 @@ static void zend_ffi_ctype_free_obj(zend_object *object) /* {{{ */ } /* }}} */ -static bool zend_ffi_is_same_type(zend_ffi_type *type1, zend_ffi_type *type2) /* {{{ */ +static bool zend_ffi_is_same_type(const zend_ffi_type *type1, const zend_ffi_type *type2) /* {{{ */ { while (1) { if (type1 == type2) { @@ -2282,10 +2280,10 @@ static int zend_ffi_ctype_compare_objects(zval *o1, zval *o2) /* {{{ */ { if (Z_TYPE_P(o1) == IS_OBJECT && Z_OBJCE_P(o1) == zend_ffi_ctype_ce && Z_TYPE_P(o2) == IS_OBJECT && Z_OBJCE_P(o2) == zend_ffi_ctype_ce) { - zend_ffi_ctype *ctype1 = (zend_ffi_ctype*)Z_OBJ_P(o1); - zend_ffi_ctype *ctype2 = (zend_ffi_ctype*)Z_OBJ_P(o2); - zend_ffi_type *type1 = ZEND_FFI_TYPE(ctype1->type); - zend_ffi_type *type2 = ZEND_FFI_TYPE(ctype2->type); + const zend_ffi_ctype *ctype1 = (zend_ffi_ctype*)Z_OBJ_P(o1); + const zend_ffi_ctype *ctype2 = (zend_ffi_ctype*)Z_OBJ_P(o2); + const zend_ffi_type *type1 = ZEND_FFI_TYPE(ctype1->type); + const zend_ffi_type *type2 = ZEND_FFI_TYPE(ctype2->type); if (zend_ffi_is_same_type(type1, type2)) { return 0; @@ -2569,7 +2567,7 @@ static zval *zend_ffi_write_var(zend_object *obj, zend_string *var_name, zval *v } /* }}} */ -static zend_result zend_ffi_pass_arg(zval *arg, zend_ffi_type *type, ffi_type **pass_type, void **arg_values, uint32_t n, zend_execute_data *execute_data) /* {{{ */ +static zend_result zend_ffi_pass_arg(zval *arg, zend_ffi_type *type, ffi_type **pass_type, void **arg_values, uint32_t n, const zend_execute_data *execute_data) /* {{{ */ { zend_long lval; double dval; @@ -2712,7 +2710,7 @@ static zend_result zend_ffi_pass_arg(zval *arg, zend_ffi_type *type, ffi_type ** } /* }}} */ -static zend_result zend_ffi_pass_var_arg(zval *arg, ffi_type **pass_type, void **arg_values, uint32_t n, zend_execute_data *execute_data) /* {{{ */ +static zend_result zend_ffi_pass_var_arg(zval *arg, ffi_type **pass_type, void **arg_values, uint32_t n, const zend_execute_data *execute_data) /* {{{ */ { ZVAL_DEREF(arg); switch (Z_TYPE_P(arg)) { @@ -2919,6 +2917,7 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */ } /* }}} */ +/* This function was manually optimized to reduce the overhead of calling native functions */ static zend_function *zend_ffi_get_func(zend_object **obj, zend_string *name, const zval *key) /* {{{ */ { zend_ffi *ffi = (zend_ffi*)*obj; @@ -3000,7 +2999,7 @@ static zend_never_inline int zend_ffi_disabled(void) /* {{{ */ } /* }}} */ -static zend_always_inline bool zend_ffi_validate_api_restriction(zend_execute_data *execute_data) /* {{{ */ +static zend_always_inline bool zend_ffi_validate_api_restriction(const zend_execute_data *execute_data) /* {{{ */ { if (EXPECTED(FFI_G(restriction) > ZEND_FFI_ENABLED)) { ZEND_ASSERT(FFI_G(restriction) == ZEND_FFI_PRELOAD); @@ -3064,8 +3063,6 @@ ZEND_METHOD(FFI, cdef) /* {{{ */ zend_string *lib = NULL; zend_ffi *ffi = NULL; DL_HANDLE handle = NULL; - char *err; - void *addr; ZEND_FFI_VALIDATE_API_RESTRICTION(); ZEND_PARSE_PARAMETERS_START(0, 2) @@ -3077,7 +3074,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */ if (lib) { handle = DL_LOAD(ZSTR_VAL(lib)); if (!handle) { - err = GET_DL_ERROR(); + char *err = GET_DL_ERROR(); #ifdef PHP_WIN32 if (err && err[0]) { zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", ZSTR_VAL(lib), err); @@ -3125,6 +3122,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */ zend_ffi_symbol *sym; ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) { + void *addr; if (sym->kind == ZEND_FFI_SYM_VAR) { addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name)); if (!addr) { @@ -3159,7 +3157,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */ } /* }}} */ -static bool zend_ffi_same_types(zend_ffi_type *old, zend_ffi_type *type) /* {{{ */ +static bool zend_ffi_same_types(const zend_ffi_type *old, const zend_ffi_type *type) /* {{{ */ { if (old == type) { return 1; @@ -3186,7 +3184,7 @@ static bool zend_ffi_same_types(zend_ffi_type *old, zend_ffi_type *type) /* {{{ } else { zend_ffi_field *old_field, *field; zend_string *key; - Bucket *b = type->record.fields.arData; + const Bucket *b = type->record.fields.arData; ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&old->record.fields, key, old_field) { while (Z_TYPE(b->val) == IS_UNDEF) { @@ -3220,7 +3218,7 @@ static bool zend_ffi_same_types(zend_ffi_type *old, zend_ffi_type *type) /* {{{ return 0; } else if (old->func.args) { zend_ffi_type *arg_type; - zval *zv = type->func.args->arPacked; + const zval *zv = type->func.args->arPacked; ZEND_HASH_PACKED_FOREACH_PTR(old->func.args, arg_type) { while (Z_TYPE_P(zv) == IS_UNDEF) { @@ -3241,7 +3239,7 @@ static bool zend_ffi_same_types(zend_ffi_type *old, zend_ffi_type *type) /* {{{ } /* }}} */ -static bool zend_ffi_same_symbols(zend_ffi_symbol *old, zend_ffi_symbol *sym) /* {{{ */ +static bool zend_ffi_same_symbols(const zend_ffi_symbol *old, const zend_ffi_symbol *sym) /* {{{ */ { if (old->kind != sym->kind || old->is_const != sym->is_const) { return 0; @@ -3257,7 +3255,7 @@ static bool zend_ffi_same_symbols(zend_ffi_symbol *old, zend_ffi_symbol *sym) /* } /* }}} */ -static bool zend_ffi_same_tags(zend_ffi_tag *old, zend_ffi_tag *tag) /* {{{ */ +static bool zend_ffi_same_tags(const zend_ffi_tag *old, const zend_ffi_tag *tag) /* {{{ */ { if (old->kind != tag->kind) { return 0; @@ -3344,7 +3342,7 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */ { struct stat buf; int fd; - char *code, *code_pos, *scope_name, *lib, *err; + char *code, *code_pos, *scope_name, *lib; size_t code_size, scope_name_len; zend_ffi *ffi; DL_HANDLE handle = NULL; @@ -3352,7 +3350,6 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */ zend_string *name; zend_ffi_symbol *sym; zend_ffi_tag *tag; - void *addr; if (stat(filename, &buf) != 0) { if (preload) { @@ -3425,7 +3422,7 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */ if (preload) { zend_error(E_WARNING, "FFI: Failed pre-loading '%s'", lib); } else { - err = GET_DL_ERROR(); + char *err = GET_DL_ERROR(); #ifdef PHP_WIN32 if (err && err[0]) { zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", lib, err); @@ -3459,6 +3456,7 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */ if (FFI_G(symbols)) { ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) { + void *addr; if (sym->kind == ZEND_FFI_SYM_VAR) { addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name)); if (!addr) { @@ -3702,7 +3700,7 @@ static void zend_ffi_throw_parser_error(const char *format, ...) /* {{{ */ } /* }}} */ -static zend_result zend_ffi_validate_vla(zend_ffi_type *type) /* {{{ */ +static zend_result zend_ffi_validate_vla(const zend_ffi_type *type) /* {{{ */ { if (!FFI_G(allow_vla) && (type->attr & ZEND_FFI_ATTR_VLA)) { zend_ffi_throw_parser_error("\"[*]\" is not allowed in other than function prototype scope at line %d", FFI_G(line)); @@ -3712,7 +3710,7 @@ static zend_result zend_ffi_validate_vla(zend_ffi_type *type) /* {{{ */ } /* }}} */ -static zend_result zend_ffi_validate_incomplete_type(zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */ +static zend_result zend_ffi_validate_incomplete_type(const zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */ { if (!allow_incomplete_tag && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) { if (FFI_G(tags)) { @@ -3756,7 +3754,7 @@ static zend_result zend_ffi_validate_incomplete_type(zend_ffi_type *type, bool a } /* }}} */ -static zend_result zend_ffi_validate_type(zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */ +static zend_result zend_ffi_validate_type(const zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */ { if (type->kind == ZEND_FFI_TYPE_VOID) { zend_ffi_throw_parser_error("void type is not allowed at line %d", FFI_G(line)); @@ -3766,7 +3764,7 @@ static zend_result zend_ffi_validate_type(zend_ffi_type *type, bool allow_incomp } /* }}} */ -static zend_result zend_ffi_validate_var_type(zend_ffi_type *type, bool allow_incomplete_array) /* {{{ */ +static zend_result zend_ffi_validate_var_type(const zend_ffi_type *type, bool allow_incomplete_array) /* {{{ */ { if (type->kind == ZEND_FFI_TYPE_FUNC) { zend_ffi_throw_parser_error("function type is not allowed at line %d", FFI_G(line)); @@ -4150,7 +4148,7 @@ ZEND_METHOD(FFI, cast) /* {{{ */ cdata->ptr = *(void**)ptr; } else if (old_type->kind == ZEND_FFI_TYPE_ARRAY && type->kind == ZEND_FFI_TYPE_POINTER - && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->array.type), ZEND_FFI_TYPE(type->pointer.type))) { cdata->ptr = &cdata->ptr_holder; + && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->array.type), ZEND_FFI_TYPE(type->pointer.type))) { cdata->ptr = &cdata->ptr_holder; cdata->ptr_holder = old_cdata->ptr; } else if (old_type->kind == ZEND_FFI_TYPE_POINTER @@ -4735,8 +4733,8 @@ ZEND_METHOD(FFI_CType, getName) /* {{{ */ ZEND_METHOD(FFI_CType, getKind) /* {{{ */ { - zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); - zend_ffi_type *type; + const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); + const zend_ffi_type *type; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); @@ -4749,8 +4747,8 @@ ZEND_METHOD(FFI_CType, getKind) /* {{{ */ ZEND_METHOD(FFI_CType, getSize) /* {{{ */ { - zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); - zend_ffi_type *type; + const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); + const zend_ffi_type *type; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); @@ -4763,8 +4761,8 @@ ZEND_METHOD(FFI_CType, getSize) /* {{{ */ ZEND_METHOD(FFI_CType, getAlignment) /* {{{ */ { - zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); - zend_ffi_type *type; + const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); + const zend_ffi_type *type; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); @@ -4777,8 +4775,8 @@ ZEND_METHOD(FFI_CType, getAlignment) /* {{{ */ ZEND_METHOD(FFI_CType, getAttributes) /* {{{ */ { - zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); - zend_ffi_type *type; + const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); + const zend_ffi_type *type; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); @@ -4791,8 +4789,8 @@ ZEND_METHOD(FFI_CType, getAttributes) /* {{{ */ ZEND_METHOD(FFI_CType, getEnumKind) /* {{{ */ { - zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); - zend_ffi_type *type; + const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); + const zend_ffi_type *type; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); @@ -4831,8 +4829,8 @@ ZEND_METHOD(FFI_CType, getArrayElementType) /* {{{ */ ZEND_METHOD(FFI_CType, getArrayLength) /* {{{ */ { - zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); - zend_ffi_type *type; + const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); + const zend_ffi_type *type; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); @@ -4871,8 +4869,8 @@ ZEND_METHOD(FFI_CType, getPointerType) /* {{{ */ ZEND_METHOD(FFI_CType, getStructFieldNames) /* {{{ */ { - zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); - zend_ffi_type *type; + const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); + const zend_ffi_type *type; HashTable *ht; zend_string* name; zval zv; @@ -4898,10 +4896,10 @@ ZEND_METHOD(FFI_CType, getStructFieldNames) /* {{{ */ ZEND_METHOD(FFI_CType, getStructFieldOffset) /* {{{ */ { - zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); - zend_ffi_type *type; + const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); + const zend_ffi_type *type; zend_string *name; - zend_ffi_field *ptr; + const zend_ffi_field *ptr; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(name) @@ -4954,8 +4952,8 @@ ZEND_METHOD(FFI_CType, getStructFieldType) /* {{{ */ ZEND_METHOD(FFI_CType, getFuncABI) /* {{{ */ { - zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); - zend_ffi_type *type; + const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); + const zend_ffi_type *type; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); @@ -4994,8 +4992,8 @@ ZEND_METHOD(FFI_CType, getFuncReturnType) /* {{{ */ ZEND_METHOD(FFI_CType, getFuncParameterCount) /* {{{ */ { - zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); - zend_ffi_type *type; + const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); + const zend_ffi_type *type; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); @@ -5909,8 +5907,8 @@ static void zend_ffi_finalize_type(zend_ffi_dcl *dcl) /* {{{ */ bool zend_ffi_is_typedef_name(const char *name, size_t name_len) /* {{{ */ { - zend_ffi_symbol *sym; - zend_ffi_type *type; + const zend_ffi_symbol *sym; + const zend_ffi_type *type; if (FFI_G(symbols)) { sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len); @@ -5952,15 +5950,13 @@ void zend_ffi_resolve_typedef(const char *name, size_t name_len, zend_ffi_dcl *d void zend_ffi_resolve_const(const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */ { - zend_ffi_symbol *sym; - if (UNEXPECTED(FFI_G(attribute_parsing))) { val->kind = ZEND_FFI_VAL_NAME; val->str = name; val->len = name_len; return; } else if (FFI_G(symbols)) { - sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len); + const zend_ffi_symbol *sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len); if (sym && sym->kind == ZEND_FFI_SYM_CONST) { val->i64 = sym->value; switch (sym->type->kind) { @@ -6010,7 +6006,7 @@ void zend_ffi_make_enum_type(zend_ffi_dcl *dcl) /* {{{ */ } /* }}} */ -void zend_ffi_add_enum_val(zend_ffi_dcl *enum_dcl, const char *name, size_t name_len, zend_ffi_val *val, int64_t *min, int64_t *max, int64_t *last) /* {{{ */ +void zend_ffi_add_enum_val(zend_ffi_dcl *enum_dcl, const char *name, size_t name_len, const zend_ffi_val *val, int64_t *min, int64_t *max, int64_t *last) /* {{{ */ { zend_ffi_symbol *sym; const zend_ffi_type *sym_type; @@ -6141,7 +6137,7 @@ void zend_ffi_make_struct_type(zend_ffi_dcl *dcl) /* {{{ */ static zend_result zend_ffi_validate_prev_field_type(zend_ffi_type *struct_type) /* {{{ */ { if (zend_hash_num_elements(&struct_type->record.fields) > 0) { - zend_ffi_field *field = NULL; + const zend_ffi_field *field = NULL; ZEND_HASH_MAP_REVERSE_FOREACH_PTR(&struct_type->record.fields, field) { break; @@ -6155,7 +6151,7 @@ static zend_result zend_ffi_validate_prev_field_type(zend_ffi_type *struct_type) } /* }}} */ -static zend_result zend_ffi_validate_field_type(zend_ffi_type *type, zend_ffi_type *struct_type) /* {{{ */ +static zend_result zend_ffi_validate_field_type(const zend_ffi_type *type, zend_ffi_type *struct_type) /* {{{ */ { if (type == struct_type) { zend_ffi_throw_parser_error("Struct/union can't contain an instance of itself at line %d", FFI_G(line)); @@ -6284,7 +6280,7 @@ void zend_ffi_add_anonymous_field(zend_ffi_dcl *struct_dcl, zend_ffi_dcl *field_ } /* }}} */ -void zend_ffi_add_bit_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl, zend_ffi_val *bits) /* {{{ */ +void zend_ffi_add_bit_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl, const zend_ffi_val *bits) /* {{{ */ { zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type); zend_ffi_type *field_type; @@ -6347,7 +6343,7 @@ void zend_ffi_add_bit_field(zend_ffi_dcl *struct_dcl, const char *name, size_t n struct_type->size = MAX(struct_type->size, ((bits->u64 + 31) / 32) * 4); } } else { - zend_ffi_field *prev_field = NULL; + const zend_ffi_field *prev_field = NULL; if (zend_hash_num_elements(&struct_type->record.fields) > 0) { ZEND_HASH_MAP_REVERSE_FOREACH_PTR(&struct_type->record.fields, prev_field) { @@ -6421,7 +6417,7 @@ void zend_ffi_make_pointer_type(zend_ffi_dcl *dcl) /* {{{ */ } /* }}} */ -static zend_result zend_ffi_validate_array_element_type(zend_ffi_type *type) /* {{{ */ +static zend_result zend_ffi_validate_array_element_type(const zend_ffi_type *type) /* {{{ */ { if (type->kind == ZEND_FFI_TYPE_FUNC) { zend_ffi_throw_parser_error("Array of functions is not allowed at line %d", FFI_G(line)); @@ -6434,10 +6430,10 @@ static zend_result zend_ffi_validate_array_element_type(zend_ffi_type *type) /* } /* }}} */ -void zend_ffi_make_array_type(zend_ffi_dcl *dcl, zend_ffi_val *len) /* {{{ */ +void zend_ffi_make_array_type(zend_ffi_dcl *dcl, const zend_ffi_val *len) /* {{{ */ { - int length = 0; - zend_ffi_type *element_type; + int64_t length = 0; + const zend_ffi_type *element_type; zend_ffi_type *type; zend_ffi_finalize_type(dcl); @@ -6481,7 +6477,7 @@ void zend_ffi_make_array_type(zend_ffi_dcl *dcl, zend_ffi_val *len) /* {{{ */ } /* }}} */ -static zend_result zend_ffi_validate_func_ret_type(zend_ffi_type *type) /* {{{ */ +static zend_result zend_ffi_validate_func_ret_type(const zend_ffi_type *type) /* {{{ */ { if (type->kind == ZEND_FFI_TYPE_FUNC) { zend_ffi_throw_parser_error("Function returning function is not allowed at line %d", FFI_G(line)); @@ -6695,7 +6691,7 @@ void zend_ffi_declare(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* { return; } else if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == 0 || (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN) { - zend_ffi_type *type = ZEND_FFI_TYPE(dcl->type); + const zend_ffi_type *type = ZEND_FFI_TYPE(dcl->type); if (type->kind == ZEND_FFI_TYPE_FUNC) { if (sym->kind == ZEND_FFI_SYM_FUNC @@ -6767,7 +6763,6 @@ void zend_ffi_declare(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* { void zend_ffi_declare_tag(const char *name, size_t name_len, zend_ffi_dcl *dcl, bool incomplete) /* {{{ */ { zend_ffi_tag *tag; - zend_ffi_type *type; if (!FFI_G(tags)) { FFI_G(tags) = pemalloc(sizeof(HashTable), FFI_G(persistent)); @@ -6810,8 +6805,10 @@ void zend_ffi_declare_tag(const char *name, size_t name_len, zend_ffi_dcl *dcl, type->attr &= ~ZEND_FFI_ATTR_INCOMPLETE_TAG; } } else { - zend_ffi_tag *tag = pemalloc(sizeof(zend_ffi_tag), FFI_G(persistent)); zend_string *tag_name = zend_string_init(name, name_len, FFI_G(persistent)); + zend_ffi_type *type; + + tag = pemalloc(sizeof(zend_ffi_tag), FFI_G(persistent)); if (dcl->flags & ZEND_FFI_DCL_STRUCT) { tag->kind = ZEND_FFI_TAG_STRUCT; @@ -6959,7 +6956,7 @@ void zend_ffi_add_attribute(zend_ffi_dcl *dcl, const char *name, size_t name_len _(format) \ _(deprecated) -void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, int n, zend_ffi_val *val) /* {{{ */ +void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, int n, const zend_ffi_val *val) /* {{{ */ { enum { VALUE_ATTRIBUTES(ATTR_ID) @@ -7074,7 +7071,7 @@ void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t na } /* }}} */ -void zend_ffi_add_msvc_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */ +void zend_ffi_add_msvc_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, const zend_ffi_val *val) /* {{{ */ { if (name_len == sizeof("align")-1 && memcmp(name, "align", sizeof("align")-1) == 0) { if ((val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64) @@ -7156,7 +7153,7 @@ void zend_ffi_align_as_type(zend_ffi_dcl *dcl, zend_ffi_dcl *align_dcl) /* {{{ * } /* }}} */ -void zend_ffi_align_as_val(zend_ffi_dcl *dcl, zend_ffi_val *align_val) /* {{{ */ +void zend_ffi_align_as_val(zend_ffi_dcl *dcl, const zend_ffi_val *align_val) /* {{{ */ { switch (align_val->kind) { case ZEND_FFI_VAL_INT32: @@ -7400,7 +7397,7 @@ void zend_ffi_align_as_val(zend_ffi_dcl *dcl, zend_ffi_val *align_val) /* {{{ */ } \ } while (0) -void zend_ffi_expr_conditional(zend_ffi_val *val, zend_ffi_val *op2, zend_ffi_val *op3) /* {{{ */ +void zend_ffi_expr_conditional(zend_ffi_val *val, const zend_ffi_val *op2, const zend_ffi_val *op3) /* {{{ */ { zend_ffi_expr_bool(val); if (val->kind == ZEND_FFI_VAL_INT32) { @@ -7437,97 +7434,97 @@ void zend_ffi_expr_bool_and(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ } /* }}} */ -void zend_ffi_expr_bw_or(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_bw_or(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_int_math(val, op2, |); } /* }}} */ -void zend_ffi_expr_bw_xor(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_bw_xor(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_int_math(val, op2, ^); } /* }}} */ -void zend_ffi_expr_bw_and(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_bw_and(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_int_math(val, op2, &); } /* }}} */ -void zend_ffi_expr_is_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_is_equal(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_cmp(val, op2, ==); } /* }}} */ -void zend_ffi_expr_is_not_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_is_not_equal(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_cmp(val, op2, !=); } /* }}} */ -void zend_ffi_expr_is_less(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_is_less(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_cmp(val, op2, <); } /* }}} */ -void zend_ffi_expr_is_greater(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_is_greater(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_cmp(val, op2, >); } /* }}} */ -void zend_ffi_expr_is_less_or_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_is_less_or_equal(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_cmp(val, op2, <=); } /* }}} */ -void zend_ffi_expr_is_greater_or_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_is_greater_or_equal(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_cmp(val, op2, >=); } /* }}} */ -void zend_ffi_expr_shift_left(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_shift_left(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_int_math(val, op2, <<); } /* }}} */ -void zend_ffi_expr_shift_right(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_shift_right(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_int_math(val, op2, >>); } /* }}} */ -void zend_ffi_expr_add(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_add(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_math(val, op2, +); } /* }}} */ -void zend_ffi_expr_sub(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_sub(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_math(val, op2, -); } /* }}} */ -void zend_ffi_expr_mul(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_mul(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_math(val, op2, *); } /* }}} */ -void zend_ffi_expr_div(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_div(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_math(val, op2, /); } /* }}} */ -void zend_ffi_expr_mod(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */ +void zend_ffi_expr_mod(zend_ffi_val *val, const zend_ffi_val *op2) /* {{{ */ { zend_ffi_expr_int_math(val, op2, %); // ??? } @@ -7758,7 +7755,7 @@ void zend_ffi_expr_sizeof_val(zend_ffi_val *val) /* {{{ */ void zend_ffi_expr_sizeof_type(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */ { - zend_ffi_type *type; + const zend_ffi_type *type; zend_ffi_finalize_type(dcl); type = ZEND_FFI_TYPE(dcl->type); diff --git a/ext/ffi/php_ffi.h b/ext/ffi/php_ffi.h index 430b8a2e568f8..ba92947e62bf4 100644 --- a/ext/ffi/php_ffi.h +++ b/ext/ffi/php_ffi.h @@ -217,45 +217,45 @@ void zend_ffi_resolve_typedef(const char *name, size_t name_len, zend_ffi_dcl *d void zend_ffi_resolve_const(const char *name, size_t name_len, zend_ffi_val *val); void zend_ffi_declare_tag(const char *name, size_t name_len, zend_ffi_dcl *dcl, bool incomplete); void zend_ffi_make_enum_type(zend_ffi_dcl *dcl); -void zend_ffi_add_enum_val(zend_ffi_dcl *enum_dcl, const char *name, size_t name_len, zend_ffi_val *val, int64_t *min, int64_t *max, int64_t *last); +void zend_ffi_add_enum_val(zend_ffi_dcl *enum_dcl, const char *name, size_t name_len, const zend_ffi_val *val, int64_t *min, int64_t *max, int64_t *last); void zend_ffi_make_struct_type(zend_ffi_dcl *dcl); void zend_ffi_add_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl); void zend_ffi_add_anonymous_field(zend_ffi_dcl *struct_dcl, zend_ffi_dcl *field_dcl); -void zend_ffi_add_bit_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl, zend_ffi_val *bits); +void zend_ffi_add_bit_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl, const zend_ffi_val *bits); void zend_ffi_adjust_struct_size(zend_ffi_dcl *dcl); void zend_ffi_make_pointer_type(zend_ffi_dcl *dcl); -void zend_ffi_make_array_type(zend_ffi_dcl *dcl, zend_ffi_val *len); +void zend_ffi_make_array_type(zend_ffi_dcl *dcl, const zend_ffi_val *len); void zend_ffi_make_func_type(zend_ffi_dcl *dcl, HashTable *args, zend_ffi_dcl *nested_dcl); void zend_ffi_add_arg(HashTable **args, const char *name, size_t name_len, zend_ffi_dcl *arg_dcl); void zend_ffi_declare(const char *name, size_t name_len, zend_ffi_dcl *dcl); void zend_ffi_add_attribute(zend_ffi_dcl *dcl, const char *name, size_t name_len); -void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, int n, zend_ffi_val *val); -void zend_ffi_add_msvc_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, zend_ffi_val *val); +void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, int n, const zend_ffi_val *val); +void zend_ffi_add_msvc_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, const zend_ffi_val *val); void zend_ffi_set_abi(zend_ffi_dcl *dcl, uint16_t abi); void zend_ffi_nested_declaration(zend_ffi_dcl *dcl, zend_ffi_dcl *nested_dcl); void zend_ffi_align_as_type(zend_ffi_dcl *dcl, zend_ffi_dcl *align_dcl); -void zend_ffi_align_as_val(zend_ffi_dcl *dcl, zend_ffi_val *align_val); +void zend_ffi_align_as_val(zend_ffi_dcl *dcl, const zend_ffi_val *align_val); void zend_ffi_validate_type_name(zend_ffi_dcl *dcl); -void zend_ffi_expr_conditional(zend_ffi_val *val, zend_ffi_val *op2, zend_ffi_val *op3); +void zend_ffi_expr_conditional(zend_ffi_val *val, const zend_ffi_val *op2, const zend_ffi_val *op3); void zend_ffi_expr_bool_or(zend_ffi_val *val, zend_ffi_val *op2); void zend_ffi_expr_bool_and(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_bw_or(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_bw_xor(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_bw_and(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_is_equal(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_is_not_equal(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_is_less(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_is_greater(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_is_less_or_equal(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_is_greater_or_equal(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_shift_left(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_shift_right(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_add(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_sub(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_mul(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_div(zend_ffi_val *val, zend_ffi_val *op2); -void zend_ffi_expr_mod(zend_ffi_val *val, zend_ffi_val *op2); +void zend_ffi_expr_bw_or(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_bw_xor(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_bw_and(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_is_equal(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_is_not_equal(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_is_less(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_is_greater(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_is_less_or_equal(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_is_greater_or_equal(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_shift_left(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_shift_right(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_add(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_sub(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_mul(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_div(zend_ffi_val *val, const zend_ffi_val *op2); +void zend_ffi_expr_mod(zend_ffi_val *val, const zend_ffi_val *op2); void zend_ffi_expr_cast(zend_ffi_val *val, zend_ffi_dcl *dcl); void zend_ffi_expr_plus(zend_ffi_val *val); void zend_ffi_expr_neg(zend_ffi_val *val); diff --git a/ext/fileinfo/fileinfo.c b/ext/fileinfo/fileinfo.c index 52172dfbd692d..c0cc8877bf991 100644 --- a/ext/fileinfo/fileinfo.c +++ b/ext/fileinfo/fileinfo.c @@ -94,14 +94,6 @@ PHP_FILEINFO_API zend_object *finfo_objects_new(zend_class_entry *class_type) } /* }}} */ -#define FINFO_SET_OPTION(magic, options) \ - if (magic_setflags(magic, options) == -1) { \ - php_error_docref(NULL, E_WARNING, "Failed to set option '" ZEND_LONG_FMT "' %d:%s", \ - options, magic_errno(magic), magic_error(magic)); \ - RETURN_FALSE; \ - } -/* }}} */ - /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(finfo) { @@ -276,189 +268,208 @@ PHP_FUNCTION(finfo_set_flags) } FILEINFO_FROM_OBJECT(finfo, self); - FINFO_SET_OPTION(finfo->magic, options) + /* We do not check the return value as it can only ever fail if options contains MAGIC_PRESERVE_ATIME + * and the system neither has utime(3) nor utimes(2). Something incredibly unlikely. */ + magic_setflags(finfo->magic, options); finfo->options = options; RETURN_TRUE; } /* }}} */ -#define FILEINFO_MODE_BUFFER 0 -#define FILEINFO_MODE_STREAM 1 -#define FILEINFO_MODE_FILE 2 - -static void _php_finfo_get_type(INTERNAL_FUNCTION_PARAMETERS, int mode, int mimetype_emu) /* {{{ */ +static const char* php_fileinfo_from_path(struct magic_set *magic, const zend_string *path, php_stream_context *context) { - zend_long options = 0; - char *ret_val = NULL, *buffer = NULL; - size_t buffer_len; - php_fileinfo *finfo = NULL; - zval *zcontext = NULL; - zval *what; - char mime_directory[] = "directory"; - struct magic_set *magic = NULL; + ZEND_ASSERT(magic != NULL); + ZEND_ASSERT(path); + ZEND_ASSERT(ZSTR_LEN(path) != 0); + ZEND_ASSERT(!zend_str_has_nul_byte(path)); + ZEND_ASSERT(context != NULL); + + /* determine if the file is a local file or remote URL */ + const char *dummy; + php_stream_statbuf ssb; + + const php_stream_wrapper *wrap = php_stream_locate_url_wrapper(ZSTR_VAL(path), &dummy, 0); + if (UNEXPECTED(wrap == NULL)) { + return NULL; + } + +#ifdef PHP_WIN32 + if (php_stream_stat_path_ex(ZSTR_VAL(path), 0, &ssb, context) == SUCCESS) { + if (ssb.sb.st_mode & S_IFDIR) { + return "directory"; + } + } +#endif - if (mimetype_emu) { + php_stream *stream = php_stream_open_wrapper_ex(ZSTR_VAL(path), "rb", REPORT_ERRORS, NULL, context); + if (!stream) { + return NULL; + } - /* mime_content_type(..) emulation */ - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &what) == FAILURE) { - RETURN_THROWS(); + const char *ret_val = NULL; + if (php_stream_stat(stream, &ssb) == SUCCESS) { + if (ssb.sb.st_mode & S_IFDIR) { + ret_val = "directory"; + } else { + ret_val = magic_stream(magic, stream); + if (UNEXPECTED(ret_val == NULL)) { + php_error_docref(NULL, E_WARNING, "Failed identify data %d:%s", magic_errno(magic), magic_error(magic)); + } } + } - switch (Z_TYPE_P(what)) { - case IS_STRING: - buffer = Z_STRVAL_P(what); - buffer_len = Z_STRLEN_P(what); - mode = FILEINFO_MODE_FILE; - break; + php_stream_close(stream); - case IS_RESOURCE: - mode = FILEINFO_MODE_STREAM; - break; + return ret_val; +} - default: - zend_argument_type_error(1, "must be of type resource|string, %s given", zend_zval_value_name(what)); - RETURN_THROWS(); - } +/* Return information about a file. */ +PHP_FUNCTION(finfo_file) +{ + zval *self; + zend_string *path = NULL; + zend_long options = 0; + zval *zcontext = NULL; + php_fileinfo *finfo = NULL; - magic = magic_open(MAGIC_MIME_TYPE); - if (magic_load(magic, NULL) == -1) { - php_error_docref(NULL, E_WARNING, "Failed to load magic database"); - goto common; - } - } else { - zval *self; - if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|lr!", &self, finfo_class_entry, &buffer, &buffer_len, &options, &zcontext) == FAILURE) { - RETURN_THROWS(); - } - FILEINFO_FROM_OBJECT(finfo, self); - magic = finfo->magic; + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OP|lr!", &self, finfo_class_entry, &path, &options, &zcontext) == FAILURE) { + RETURN_THROWS(); + } + FILEINFO_FROM_OBJECT(finfo, self); + struct magic_set *magic = finfo->magic; + + if (UNEXPECTED(ZSTR_LEN(path) == 0)) { + zend_argument_must_not_be_empty_error(2); + RETURN_THROWS(); + } + php_stream_context *context = php_stream_context_from_zval(zcontext, false); + if (!context) { + RETURN_THROWS(); } /* Set options for the current file/buffer. */ if (options) { - FINFO_SET_OPTION(magic, options) + /* We do not check the return value as it can only ever fail if options contains MAGIC_PRESERVE_ATIME + * and the system neither has utime(3) nor utimes(2). Something incredibly unlikely. */ + magic_setflags(magic, options); } - switch (mode) { - case FILEINFO_MODE_BUFFER: - { - ret_val = (char *) magic_buffer(magic, buffer, buffer_len); - break; - } - - case FILEINFO_MODE_STREAM: - { - php_stream *stream; - zend_off_t streampos; - - php_stream_from_zval_no_verify(stream, what); - if (!stream) { - goto common; - } - - streampos = php_stream_tell(stream); /* remember stream position for restoration */ - php_stream_seek(stream, 0, SEEK_SET); + const char *ret_val = php_fileinfo_from_path(magic, path, context); + /* Restore options */ + if (options) { + magic_setflags(magic, finfo->options); + } - ret_val = (char *) magic_stream(magic, stream); + if (UNEXPECTED(ret_val == NULL)) { + RETURN_FALSE; + } else { + RETURN_STRING(ret_val); + } +} - php_stream_seek(stream, streampos, SEEK_SET); - break; - } +/* Return information about a string buffer. */ +PHP_FUNCTION(finfo_buffer) +{ + zval *self; + zend_string *buffer = NULL; + zend_long options = 0; + zval *dummy_context = NULL; + php_fileinfo *finfo = NULL; - case FILEINFO_MODE_FILE: - { - /* determine if the file is a local file or remote URL */ - const char *tmp2; - php_stream_wrapper *wrap; - php_stream_statbuf ssb; - - // Implementation is used for both finfo_file() and mimetype_emu() - int buffer_param_num = (mimetype_emu ? 1 : 2); - if (buffer == NULL || buffer_len == 0) { - zend_argument_must_not_be_empty_error(buffer_param_num); - goto clean; - } - if (CHECK_NULL_PATH(buffer, buffer_len)) { - zend_argument_type_error(buffer_param_num, "must not contain any null bytes"); - goto clean; - } + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OS|lr!", &self, finfo_class_entry, &buffer, &options, &dummy_context) == FAILURE) { + RETURN_THROWS(); + } + FILEINFO_FROM_OBJECT(finfo, self); + struct magic_set *magic = finfo->magic; - wrap = php_stream_locate_url_wrapper(buffer, &tmp2, 0); + /* Set options for the current file/buffer. */ + if (options) { + magic_setflags(magic, options); + } - if (wrap) { - php_stream *stream; - php_stream_context *context = php_stream_context_from_zval(zcontext, 0); + const char *ret_val = magic_buffer(magic, ZSTR_VAL(buffer), ZSTR_LEN(buffer)); -#ifdef PHP_WIN32 - if (php_stream_stat_path_ex(buffer, 0, &ssb, context) == SUCCESS) { - if (ssb.sb.st_mode & S_IFDIR) { - ret_val = mime_directory; - goto common; - } - } -#endif + /* Restore options */ + if (options) { + magic_setflags(magic, finfo->options); + } - stream = php_stream_open_wrapper_ex(buffer, "rb", REPORT_ERRORS, NULL, context); + if (UNEXPECTED(ret_val == NULL)) { + php_error_docref(NULL, E_WARNING, "Failed identify data %d:%s", magic_errno(magic), magic_error(magic)); + RETURN_FALSE; + } else { + RETURN_STRING(ret_val); + } +} - if (!stream) { - RETVAL_FALSE; - goto clean; - } +/* Return content-type for file */ +PHP_FUNCTION(mime_content_type) +{ + zval *path_or_stream; + const zend_string *path = NULL; + php_stream *stream = NULL; + struct magic_set *magic = NULL; - if (php_stream_stat(stream, &ssb) == SUCCESS) { - if (ssb.sb.st_mode & S_IFDIR) { - ret_val = mime_directory; - } else { - ret_val = (char *)magic_stream(magic, stream); - } - } + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &path_or_stream) == FAILURE) { + RETURN_THROWS(); + } - php_stream_close(stream); + switch (Z_TYPE_P(path_or_stream)) { + case IS_STRING: + path = Z_STR_P(path_or_stream); + if (UNEXPECTED(ZSTR_LEN(path) == 0)) { + zend_argument_must_not_be_empty_error(1); + RETURN_THROWS(); + } + if (UNEXPECTED(zend_str_has_nul_byte(path))) { + zend_argument_type_error(1, "must not contain any null bytes"); + RETURN_THROWS(); } break; - } - EMPTY_SWITCH_DEFAULT_CASE() + + case IS_RESOURCE: + php_stream_from_zval(stream, path_or_stream); + break; + + default: + zend_argument_type_error(1, "must be of type resource|string, %s given", zend_zval_value_name(path_or_stream)); + RETURN_THROWS(); } -common: - if (ret_val) { - RETVAL_STRING(ret_val); - } else { - php_error_docref(NULL, E_WARNING, "Failed identify data %d:%s", magic_errno(magic), magic_error(magic)); - RETVAL_FALSE; + magic = magic_open(MAGIC_MIME_TYPE); + if (UNEXPECTED(magic == NULL)) { + php_error_docref(NULL, E_WARNING, "Failed to load magic database"); + RETURN_FALSE; } -clean: - if (mimetype_emu) { + if (UNEXPECTED(magic_load(magic, NULL) == -1)) { + php_error_docref(NULL, E_WARNING, "Failed identify data %d:%s", magic_errno(magic), magic_error(magic)); magic_close(magic); + RETURN_FALSE; } - /* Restore options */ - if (options) { - FINFO_SET_OPTION(magic, finfo->options) - } - return; -} -/* }}} */ + const char *ret_val; + if (path) { + php_stream_context *context = php_stream_context_get_default(false); + ret_val = php_fileinfo_from_path(magic, path, context); + } else { + /* remember stream position for restoration */ + zend_off_t current_stream_pos = php_stream_tell(stream); + php_stream_seek(stream, 0, SEEK_SET); -/* {{{ Return information about a file. */ -PHP_FUNCTION(finfo_file) -{ - _php_finfo_get_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, FILEINFO_MODE_FILE, 0); -} -/* }}} */ + ret_val = magic_stream(magic, stream); + if (UNEXPECTED(ret_val == NULL)) { + php_error_docref(NULL, E_WARNING, "Failed identify data %d:%s", magic_errno(magic), magic_error(magic)); + } -/* {{{ Return information about a string buffer. */ -PHP_FUNCTION(finfo_buffer) -{ - _php_finfo_get_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, FILEINFO_MODE_BUFFER, 0); -} -/* }}} */ + php_stream_seek(stream, current_stream_pos, SEEK_SET); + } -/* {{{ Return content-type for file */ -PHP_FUNCTION(mime_content_type) -{ - _php_finfo_get_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, -1, 1); + if (UNEXPECTED(ret_val == NULL)) { + RETVAL_FALSE; + } else { + RETVAL_STRING(ret_val); + } + magic_close(magic); } -/* }}} */ diff --git a/ext/fileinfo/tests/finfo_file_001.phpt b/ext/fileinfo/tests/finfo_file_001.phpt index 1e31b8ad1c049..737b8db53ff77 100644 --- a/ext/fileinfo/tests/finfo_file_001.phpt +++ b/ext/fileinfo/tests/finfo_file_001.phpt @@ -8,7 +8,7 @@ fileinfo $fp = finfo_open(); try { var_dump(finfo_file($fp, "\0")); -} catch (\TypeError $e) { +} catch (\ValueError $e) { echo $e->getMessage() . \PHP_EOL; } try { diff --git a/ext/fileinfo/tests/finfo_file_basic.phpt b/ext/fileinfo/tests/finfo_file_basic.phpt index e6f2b1e8570d5..4545a3063a7fe 100644 --- a/ext/fileinfo/tests/finfo_file_basic.phpt +++ b/ext/fileinfo/tests/finfo_file_basic.phpt @@ -15,7 +15,7 @@ var_dump( finfo_file( $finfo, __FILE__, FILEINFO_CONTINUE ) ); var_dump( finfo_file( $finfo, $magicFile ) ); try { var_dump( finfo_file( $finfo, $magicFile.chr(0).$magicFile) ); -} catch (\TypeError $e) { +} catch (\ValueError $e) { echo $e->getMessage() . \PHP_EOL; } diff --git a/ext/fileinfo/tests/gh18267.phpt b/ext/fileinfo/tests/gh18267.phpt new file mode 100644 index 0000000000000..ba7647288d1de --- /dev/null +++ b/ext/fileinfo/tests/gh18267.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-18267 finfo_file() assertion trigger on NULL stream context +--EXTENSIONS-- +fileinfo +--FILE-- +file("test",FILEINFO_NONE, STDERR); +} catch (\TypeError $e) { + echo $e->getMessage(); +} +--EXPECT-- +finfo::file(): supplied resource is not a valid Stream-Context resource diff --git a/ext/filter/filter.c b/ext/filter/filter.c index 9c380163823cd..50eefb440d67a 100644 --- a/ext/filter/filter.c +++ b/ext/filter/filter.c @@ -100,9 +100,9 @@ ZEND_GET_MODULE(filter) static PHP_INI_MH(UpdateDefaultFilter) /* {{{ */ { - int i, size = sizeof(filter_list) / sizeof(filter_list_entry); + int size = sizeof(filter_list) / sizeof(filter_list_entry); - for (i = 0; i < size; ++i) { + for (int i = 0; i < size; ++i) { if ((strcasecmp(ZSTR_VAL(new_value), filter_list[i].name) == 0)) { IF_G(default_filter) = filter_list[i].id; if (IF_G(default_filter) != FILTER_DEFAULT) { @@ -144,9 +144,6 @@ ZEND_TSRMLS_CACHE_UPDATE(); ZVAL_UNDEF(&filter_globals->cookie_array); ZVAL_UNDEF(&filter_globals->env_array); ZVAL_UNDEF(&filter_globals->server_array); -#if 0 - ZVAL_UNDEF(&filter_globals->session_array); -#endif filter_globals->default_filter = FILTER_DEFAULT; } /* }}} */ @@ -189,9 +186,6 @@ PHP_RSHUTDOWN_FUNCTION(filter) VAR_ARRAY_COPY_DTOR(cookie_array) VAR_ARRAY_COPY_DTOR(server_array) VAR_ARRAY_COPY_DTOR(env_array) -#if 0 - VAR_ARRAY_COPY_DTOR(session_array) -#endif return SUCCESS; } /* }}} */ @@ -234,13 +228,10 @@ static unsigned int php_sapi_filter_init(void) ZVAL_UNDEF(&IF_G(cookie_array)); ZVAL_UNDEF(&IF_G(server_array)); ZVAL_UNDEF(&IF_G(env_array)); -#if 0 - ZVAL_UNDEF(&IF_G(session_array)); -#endif return SUCCESS; } -static void php_zval_filter(zval *value, zend_long filter, zend_long flags, zval *options, char* charset, bool copy) /* {{{ */ +static void php_zval_filter(zval *value, zend_long filter, zend_long flags, zval *options, char* charset) /* {{{ */ { filter_list_entry filter_func; @@ -336,7 +327,7 @@ static unsigned int php_sapi_filter(int arg, const char *var, char **val, size_t /* Register mangled variable */ if (IF_G(default_filter) != FILTER_UNSAFE_RAW) { ZVAL_STRINGL(&new_var, *val, val_len); - php_zval_filter(&new_var, IF_G(default_filter), IF_G(default_filter_flags), NULL, NULL, 0); + php_zval_filter(&new_var, IF_G(default_filter), IF_G(default_filter_flags), NULL, NULL); } else { ZVAL_STRINGL(&new_var, *val, val_len); } @@ -365,7 +356,7 @@ static unsigned int php_sapi_filter(int arg, const char *var, char **val, size_t } /* }}} */ -static void php_zval_filter_recursive(zval *value, zend_long filter, zend_long flags, zval *options, char *charset, bool copy) /* {{{ */ +static void php_zval_filter_recursive(zval *value, zend_long filter, zend_long flags, zval *options, char *charset) /* {{{ */ { if (Z_TYPE_P(value) == IS_ARRAY) { zval *element; @@ -379,14 +370,14 @@ static void php_zval_filter_recursive(zval *value, zend_long filter, zend_long f ZVAL_DEREF(element); if (Z_TYPE_P(element) == IS_ARRAY) { SEPARATE_ARRAY(element); - php_zval_filter_recursive(element, filter, flags, options, charset, copy); + php_zval_filter_recursive(element, filter, flags, options, charset); } else { - php_zval_filter(element, filter, flags, options, charset, copy); + php_zval_filter(element, filter, flags, options, charset); } } ZEND_HASH_FOREACH_END(); Z_UNPROTECT_RECURSION_P(value); } else { - php_zval_filter(value, filter, flags, options, charset, copy); + php_zval_filter(value, filter, flags, options, charset); } } /* }}} */ @@ -458,10 +449,9 @@ PHP_FUNCTION(filter_has_var) static void php_filter_call( zval *filtered, zend_long filter, HashTable *filter_args_ht, zend_long filter_args_long, - const int copy, zend_long filter_flags + zend_long filter_flags ) /* {{{ */ { zval *options = NULL; - zval *option; char *charset = NULL; if (!filter_args_ht) { @@ -476,6 +466,7 @@ static void php_filter_call( filter = filter_args_long; } } else { + zval *option; if ((option = zend_hash_str_find(filter_args_ht, "filter", sizeof("filter") - 1)) != NULL) { filter = zval_get_long(option); } @@ -510,7 +501,7 @@ static void php_filter_call( } return; } - php_zval_filter_recursive(filtered, filter, filter_flags, options, charset, copy); + php_zval_filter_recursive(filtered, filter, filter_flags, options, charset); return; } if (filter_flags & FILTER_REQUIRE_ARRAY) { @@ -523,7 +514,7 @@ static void php_filter_call( return; } - php_zval_filter(filtered, filter, filter_flags, options, charset, copy); + php_zval_filter(filtered, filter, filter_flags, options, charset); if (filter_flags & FILTER_FORCE_ARRAY) { zval tmp; ZVAL_COPY_VALUE(&tmp, filtered); @@ -536,14 +527,13 @@ static void php_filter_call( static void php_filter_array_handler(zval *input, HashTable *op_ht, zend_long op_long, zval *return_value, bool add_empty ) /* {{{ */ { - zend_string *arg_key; - zval *tmp, *arg_elm; - if (!op_ht) { ZVAL_DUP(return_value, input); - php_filter_call(return_value, -1, NULL, op_long, 0, FILTER_REQUIRE_ARRAY); + php_filter_call(return_value, -1, NULL, op_long, FILTER_REQUIRE_ARRAY); } else { array_init(return_value); + zend_string *arg_key; + zval *arg_elm; ZEND_HASH_FOREACH_STR_KEY_VAL(op_ht, arg_key, arg_elm) { if (arg_key == NULL) { @@ -554,6 +544,7 @@ static void php_filter_array_handler(zval *input, HashTable *op_ht, zend_long op zend_argument_value_error(2, "cannot contain empty keys"); RETURN_THROWS(); } + zval *tmp; if ((tmp = zend_hash_find(Z_ARRVAL_P(input), arg_key)) == NULL) { if (add_empty) { add_assoc_null_ex(return_value, ZSTR_VAL(arg_key), ZSTR_LEN(arg_key)); @@ -565,7 +556,7 @@ static void php_filter_array_handler(zval *input, HashTable *op_ht, zend_long op php_filter_call(&nval, -1, Z_TYPE_P(arg_elm) == IS_ARRAY ? Z_ARRVAL_P(arg_elm) : NULL, Z_TYPE_P(arg_elm) == IS_ARRAY ? 0 : zval_get_long(arg_elm), - 0, FILTER_REQUIRE_SCALAR + FILTER_REQUIRE_SCALAR ); zend_hash_update(Z_ARRVAL_P(return_value), arg_key, &nval); } @@ -603,10 +594,10 @@ PHP_FUNCTION(filter_input) if (!input || (tmp = zend_hash_find(Z_ARRVAL_P(input), var)) == NULL) { zend_long filter_flags = 0; - zval *option, *opt, *def; if (!filter_args_ht) { filter_flags = filter_args_long; } else { + zval *option, *opt, *def; if ((option = zend_hash_str_find(filter_args_ht, "flags", sizeof("flags") - 1)) != NULL) { filter_flags = zval_get_long(option); } @@ -634,7 +625,7 @@ PHP_FUNCTION(filter_input) ZVAL_DUP(return_value, tmp); - php_filter_call(return_value, filter, filter_args_ht, filter_args_long, 1, FILTER_REQUIRE_SCALAR); + php_filter_call(return_value, filter, filter_args_ht, filter_args_long, FILTER_REQUIRE_SCALAR); } /* }}} */ @@ -660,7 +651,7 @@ PHP_FUNCTION(filter_var) ZVAL_DUP(return_value, data); - php_filter_call(return_value, filter, filter_args_ht, filter_args_long, 1, FILTER_REQUIRE_SCALAR); + php_filter_call(return_value, filter, filter_args_ht, filter_args_long, FILTER_REQUIRE_SCALAR); } /* }}} */ @@ -726,14 +717,14 @@ PHP_FUNCTION(filter_var_array) /* {{{ Returns a list of all supported filters */ PHP_FUNCTION(filter_list) { - int i, size = sizeof(filter_list) / sizeof(filter_list_entry); + int size = sizeof(filter_list) / sizeof(filter_list_entry); if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); } array_init(return_value); - for (i = 0; i < size; ++i) { + for (int i = 0; i < size; ++i) { add_next_index_string(return_value, (char *)filter_list[i].name); } } @@ -742,7 +733,6 @@ PHP_FUNCTION(filter_list) /* {{{ Returns the filter ID belonging to a named filter */ PHP_FUNCTION(filter_id) { - int i; size_t filter_len; int size = sizeof(filter_list) / sizeof(filter_list_entry); char *filter; @@ -751,7 +741,7 @@ PHP_FUNCTION(filter_id) RETURN_THROWS(); } - for (i = 0; i < size; ++i) { + for (int i = 0; i < size; ++i) { if (strcmp(filter_list[i].name, filter) == 0) { RETURN_LONG(filter_list[i].id); } diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c index d0d60c00ebc63..0dd307122345c 100644 --- a/ext/filter/logical_filters.c +++ b/ext/filter/logical_filters.c @@ -89,16 +89,17 @@ #define FORMAT_IPV4 4 #define FORMAT_IPV6 6 -static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]); +static bool _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]); -static int php_filter_parse_int(const char *str, size_t str_len, zend_long *ret) { /* {{{ */ +static bool php_filter_parse_int(const char *str, size_t str_len, zend_long *ret) { /* {{{ */ zend_long ctx_value; - int sign = 0, digit = 0; + bool is_negative = false; + int digit = 0; const char *end = str + str_len; switch (*str) { case '-': - sign = 1; + is_negative = true; ZEND_FALLTHROUGH; case '+': str++; @@ -108,43 +109,43 @@ static int php_filter_parse_int(const char *str, size_t str_len, zend_long *ret) if (*str == '0' && str + 1 == end) { /* Special cases: +0 and -0 */ - return 1; + return true; } /* must start with 1..9*/ if (str < end && *str >= '1' && *str <= '9') { - ctx_value = ((sign)?-1:1) * ((*(str++)) - '0'); + ctx_value = (is_negative?-1:1) * ((*(str++)) - '0'); } else { - return -1; + return false; } if ((end - str > MAX_LENGTH_OF_LONG - 1) /* number too long */ || (SIZEOF_LONG == 4 && (end - str == MAX_LENGTH_OF_LONG - 1) && *str > '2')) { /* overflow */ - return -1; + return false; } while (str < end) { if (*str >= '0' && *str <= '9') { digit = (*(str++) - '0'); - if ( (!sign) && ctx_value <= (ZEND_LONG_MAX-digit)/10 ) { + if ( (!is_negative) && ctx_value <= (ZEND_LONG_MAX-digit)/10 ) { ctx_value = (ctx_value * 10) + digit; - } else if ( sign && ctx_value >= (ZEND_LONG_MIN+digit)/10) { + } else if ( is_negative && ctx_value >= (ZEND_LONG_MIN+digit)/10) { ctx_value = (ctx_value * 10) - digit; } else { - return -1; + return false; } } else { - return -1; + return false; } } *ret = ctx_value; - return 1; + return true; } /* }}} */ -static int php_filter_parse_octal(const char *str, size_t str_len, zend_long *ret) { /* {{{ */ +static bool php_filter_parse_octal(const char *str, size_t str_len, zend_long *ret) { /* {{{ */ zend_ulong ctx_value = 0; const char *end = str + str_len; @@ -154,20 +155,20 @@ static int php_filter_parse_octal(const char *str, size_t str_len, zend_long *re if ((ctx_value > ((zend_ulong)(~(zend_long)0)) / 8) || ((ctx_value = ctx_value * 8) > ((zend_ulong)(~(zend_long)0)) - n)) { - return -1; + return false; } ctx_value += n; } else { - return -1; + return false; } } *ret = (zend_long)ctx_value; - return 1; + return true; } /* }}} */ -static int php_filter_parse_hex(const char *str, size_t str_len, zend_long *ret) { /* {{{ */ +static bool php_filter_parse_hex(const char *str, size_t str_len, zend_long *ret) { /* {{{ */ zend_ulong ctx_value = 0; const char *end = str + str_len; zend_ulong n; @@ -180,17 +181,17 @@ static int php_filter_parse_hex(const char *str, size_t str_len, zend_long *ret) } else if (*str >= 'A' && *str <= 'F') { n = ((*(str++)) - ('A' - 10)); } else { - return -1; + return false; } if ((ctx_value > ((zend_ulong)(~(zend_long)0)) / 16) || ((ctx_value = ctx_value * 16) > ((zend_ulong)(~(zend_long)0)) - n)) { - return -1; + return false; } ctx_value += n; } *ret = (zend_long)ctx_value; - return 1; + return true; } /* }}} */ @@ -199,11 +200,11 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ zval *option_val; zend_long min_range, max_range, option_flags; int min_range_set, max_range_set; - int allow_octal = 0, allow_hex = 0; + bool allow_octal = false, allow_hex = false; size_t len; - int error = 0; + bool error = false; zend_long ctx_value; - char *p; + const char *p; /* Parse options */ FETCH_LONG_OPTION(min_range, "min_range"); @@ -217,11 +218,11 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ } if (option_flags & FILTER_FLAG_ALLOW_OCTAL) { - allow_octal = 1; + allow_octal = true; } if (option_flags & FILTER_FLAG_ALLOW_HEX) { - allow_hex = 1; + allow_hex = true; } /* Start the validating loop */ @@ -237,8 +238,8 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ if (len == 0) { RETURN_VALIDATION_FAILED } - if (php_filter_parse_hex(p, len, &ctx_value) < 0) { - error = 1; + if (!php_filter_parse_hex(p, len, &ctx_value)) { + error = true; } } else if (allow_octal) { /* Support explicit octal prefix notation */ @@ -248,19 +249,19 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ RETURN_VALIDATION_FAILED } } - if (php_filter_parse_octal(p, len, &ctx_value) < 0) { - error = 1; + if (!php_filter_parse_octal(p, len, &ctx_value)) { + error = true; } } else if (len != 0) { - error = 1; + error = true; } } else { - if (php_filter_parse_int(p, len, &ctx_value) < 0) { - error = 1; + if (!php_filter_parse_int(p, len, &ctx_value)) { + error = true; } } - if (error > 0 || (min_range_set && (ctx_value < min_range)) || (max_range_set && (ctx_value > max_range))) { + if (error || (min_range_set && (ctx_value < min_range)) || (max_range_set && (ctx_value > max_range))) { RETURN_VALIDATION_FAILED } else { zval_ptr_dtor(value); @@ -272,7 +273,7 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ void php_filter_boolean(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ { - char *str = Z_STRVAL_P(value); + const char *str = Z_STRVAL_P(value); size_t len = Z_STRLEN_P(value); int ret; @@ -342,7 +343,7 @@ void php_filter_boolean(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ void php_filter_float(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ { size_t len; - char *str, *end; + const char *str, *end; char *num, *p; zval *option_val; char *decimal; @@ -359,7 +360,7 @@ void php_filter_float(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ double min_range, max_range; int min_range_set, max_range_set; - int first, n; + int n; len = Z_STRLEN_P(value); str = Z_STRVAL_P(value); @@ -398,7 +399,7 @@ void php_filter_float(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ if (str < end && (*str == '+' || *str == '-')) { *p++ = *str++; } - first = 1; + bool first = true; while (1) { n = 0; while (str < end && *str >= '0' && *str <= '9') { @@ -431,7 +432,7 @@ void php_filter_float(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ if (first?(n < 1 || n > 3):(n != 3)) { goto error; } - first = 0; + first = false; str++; } else { goto error; @@ -504,16 +505,16 @@ void php_filter_validate_regexp(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ } } -static int _php_filter_validate_domain(char * domain, size_t len, zend_long flags) /* {{{ */ +static bool php_filter_validate_domain_ex(const zend_string *domain, zend_long flags) /* {{{ */ { - char *e, *s, *t; + const char *e, *s, *t; size_t l; int hostname = flags & FILTER_FLAG_HOSTNAME; unsigned char i = 1; - s = domain; - l = len; - e = domain + l; + s = ZSTR_VAL(domain); + l = ZSTR_LEN(domain); + e = s + l; t = e - 1; /* Ignore trailing dot */ @@ -524,26 +525,26 @@ static int _php_filter_validate_domain(char * domain, size_t len, zend_long flag /* The total length cannot exceed 253 characters (final dot not included) */ if (l > 253) { - return 0; + return false; } /* First char must be alphanumeric */ if(*s == '.' || (hostname && !isalnum((int)*(unsigned char *)s))) { - return 0; + return false; } while (s < e) { if (*s == '.') { /* The first and the last character of a label must be alphanumeric */ if (*(s + 1) == '.' || (hostname && (!isalnum((int)*(unsigned char *)(s - 1)) || !isalnum((int)*(unsigned char *)(s + 1))))) { - return 0; + return false; } /* Reset label length counter */ i = 1; } else { if (i > 63 || (hostname && (*s != '-' || *(s + 1) == '\0') && !isalnum((int)*(unsigned char *)s))) { - return 0; + return false; } i++; @@ -552,40 +553,40 @@ static int _php_filter_validate_domain(char * domain, size_t len, zend_long flag s++; } - return 1; + return true; } /* }}} */ void php_filter_validate_domain(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ { - if (!_php_filter_validate_domain(Z_STRVAL_P(value), Z_STRLEN_P(value), flags)) { + if (!php_filter_validate_domain_ex(Z_STR_P(value), flags)) { RETURN_VALIDATION_FAILED } } /* }}} */ -static int is_userinfo_valid(zend_string *str) +static bool is_userinfo_valid(const zend_string *str) { - const char *valid = "-._~!$&'()*+,;=:"; const char *p = ZSTR_VAL(str); while (p - ZSTR_VAL(str) < ZSTR_LEN(str)) { + static const char *valid = "-._~!$&'()*+,;=:"; if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) { p++; } else if (*p == '%' && p - ZSTR_VAL(str) <= ZSTR_LEN(str) - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) { p += 3; } else { - return 0; + return false; } } - return 1; + return true; } -static bool php_filter_is_valid_ipv6_hostname(const char *s, size_t l) +static bool php_filter_is_valid_ipv6_hostname(const zend_string *s) { - const char *e = s + l; + const char *e = ZSTR_VAL(s) + ZSTR_LEN(s); const char *t = e - 1; - return *s == '[' && *t == ']' && _php_filter_validate_ipv6(s + 1, l - 2, NULL); + return *ZSTR_VAL(s) == '[' && *t == ']' && _php_filter_validate_ipv6(ZSTR_VAL(s) + 1, ZSTR_LEN(s) - 2, NULL); } void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ @@ -608,22 +609,17 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ if (url->scheme != NULL && (zend_string_equals_literal_ci(url->scheme, "http") || zend_string_equals_literal_ci(url->scheme, "https"))) { - const char *s; - size_t l; if (url->host == NULL) { goto bad_url; } - s = ZSTR_VAL(url->host); - l = ZSTR_LEN(url->host); - if ( /* An IPv6 enclosed by square brackets is a valid hostname.*/ - !php_filter_is_valid_ipv6_hostname(s, l) && + !php_filter_is_valid_ipv6_hostname(url->host) && /* Validate domain. * This includes a loose check for an IPv4 address. */ - !_php_filter_validate_domain(ZSTR_VAL(url->host), l, FILTER_FLAG_HOSTNAME) + !php_filter_validate_domain_ex(url->host, FILTER_FLAG_HOSTNAME) ) { php_url_free(url); RETURN_VALIDATION_FAILED @@ -723,16 +719,16 @@ void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ } /* }}} */ -static int _php_filter_validate_ipv4(char *str, size_t str_len, int *ip) /* {{{ */ +static bool _php_filter_validate_ipv4(const char *str, size_t str_len, int *ip) /* {{{ */ { const char *end = str + str_len; int num, m; int n = 0; while (str < end) { - int leading_zero; + bool leading_zero; if (*str < '0' || *str > '9') { - return 0; + return false; } leading_zero = (*str == '0'); m = 1; @@ -740,30 +736,31 @@ static int _php_filter_validate_ipv4(char *str, size_t str_len, int *ip) /* {{{ while (str < end && (*str >= '0' && *str <= '9')) { num = num * 10 + ((*(str++)) - '0'); if (num > 255 || ++m > 3) { - return 0; + return false; } } /* don't allow a leading 0; that introduces octal numbers, * which we don't support */ if (leading_zero && (num != 0 || m > 1)) - return 0; + return false; ip[n++] = num; if (n == 4) { return str == end; } else if (str >= end || *(str++) != '.') { - return 0; + return false; } } - return 0; + return false; } /* }}} */ -static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]) /* {{{ */ +static bool _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]) /* {{{ */ { int compressed_pos = -1; int blocks = 0; - int num, n, i; - char *ipv4; + unsigned int num, n; + int i; + const char *ipv4; const char *end; int ip4elm[4]; const char *s = str; @@ -802,11 +799,11 @@ static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]) if (*str == ':') { if (++str >= end) { /* cannot end in : without previous : */ - return 0; + return false; } if (*str == ':') { if (compressed_pos >= 0) { - return 0; + return false; } if (ip && blocks < 8) { ip[blocks] = -1; @@ -814,13 +811,13 @@ static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]) compressed_pos = blocks++; /* :: means 1 or more 16-bit 0 blocks */ if (++str == end) { if (blocks > 8) { - return 0; + return false; } goto fixup_ip; } } else if ((str - 1) == s) { /* don't allow leading : without another : following */ - return 0; + return false; } } num = n = 0; @@ -841,10 +838,10 @@ static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]) ip[blocks] = num; } if (n < 1 || n > 4) { - return 0; + return false; } if (++blocks > 8) - return 0; + return false; } fixup_ip: @@ -1010,7 +1007,7 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ } } else if (mode == FORMAT_IPV6) { - if (_php_filter_validate_ipv6(Z_STRVAL_P(value), Z_STRLEN_P(value), ip) < 1) { + if (!_php_filter_validate_ipv6(Z_STRVAL_P(value), Z_STRLEN_P(value), ip)) { RETURN_VALIDATION_FAILED } @@ -1035,9 +1032,9 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ void php_filter_validate_mac(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ { - char *input = Z_STRVAL_P(value); + const char *input = Z_STRVAL_P(value); size_t input_len = Z_STRLEN_P(value); - int tokens, length, i, offset, exp_separator_set; + int tokens, length, exp_separator_set; size_t exp_separator_len; char separator; char *exp_separator; @@ -1080,14 +1077,14 @@ void php_filter_validate_mac(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ * a hexadecimal number followed by a separator character. (With the * exception of the last token which does not have the separator.) */ - for (i = 0; i < tokens; i++) { - offset = i * (length + 1); + for (int i = 0; i < tokens; i++) { + int offset = i * (length + 1); if (i < tokens - 1 && input[offset + length] != separator) { /* The current token did not end with e.g. a "." */ RETURN_VALIDATION_FAILED } - if (php_filter_parse_hex(input + offset, length, &ret) < 0) { + if (!php_filter_parse_hex(input + offset, length, &ret)) { /* The current token is no valid hexadecimal digit */ RETURN_VALIDATION_FAILED } diff --git a/ext/filter/php_filter.h b/ext/filter/php_filter.h index 4587a375e43b8..f782907898fca 100644 --- a/ext/filter/php_filter.h +++ b/ext/filter/php_filter.h @@ -42,9 +42,6 @@ ZEND_BEGIN_MODULE_GLOBALS(filter) zval cookie_array; zval env_array; zval server_array; -#if 0 - zval session_array; -#endif zend_long default_filter; zend_long default_filter_flags; ZEND_END_MODULE_GLOBALS(filter) diff --git a/ext/filter/sanitizing_filters.c b/ext/filter/sanitizing_filters.c index 647d559c1df56..7f8b4948d5818 100644 --- a/ext/filter/sanitizing_filters.c +++ b/ext/filter/sanitizing_filters.c @@ -60,12 +60,12 @@ static const unsigned char hexchars[] = "0123456789ABCDEF"; #define DEFAULT_URL_ENCODE LOWALPHA HIALPHA DIGIT "-._" -static void php_filter_encode_url(zval *value, const unsigned char* chars, const int char_len, int high, int low, int encode_nul) +static void php_filter_encode_url(zval *value, const unsigned char* chars, const int char_len) { unsigned char *p; unsigned char tmp[256]; - unsigned char *s = (unsigned char *)chars; - unsigned char *e = s + char_len; + const unsigned char *s = chars; + const unsigned char *e = s + char_len; zend_string *str; memset(tmp, 1, sizeof(tmp)-1); @@ -75,8 +75,8 @@ static void php_filter_encode_url(zval *value, const unsigned char* chars, const } str = zend_string_safe_alloc(Z_STRLEN_P(value), 3, 0, 0); - p = (unsigned char *) ZSTR_VAL(str); - s = (unsigned char *) Z_STRVAL_P(value); + p = (unsigned char*)ZSTR_VAL(str); + s = (const unsigned char*)Z_STRVAL_P(value); e = s + Z_STRLEN_P(value); while (s < e) { @@ -90,15 +90,14 @@ static void php_filter_encode_url(zval *value, const unsigned char* chars, const s++; } *p = '\0'; - ZSTR_LEN(str) = p - (unsigned char *)ZSTR_VAL(str); + ZSTR_LEN(str) = p - (const unsigned char *)ZSTR_VAL(str); zval_ptr_dtor(value); ZVAL_NEW_STR(value, str); } static void php_filter_strip(zval *value, zend_long flags) { - unsigned char *str; - size_t i; + const unsigned char *str; size_t c; zend_string *buf; @@ -107,10 +106,10 @@ static void php_filter_strip(zval *value, zend_long flags) return; } - str = (unsigned char *)Z_STRVAL_P(value); + str = (const unsigned char *)Z_STRVAL_P(value); buf = zend_string_alloc(Z_STRLEN_P(value), 0); c = 0; - for (i = 0; i < Z_STRLEN_P(value); i++) { + for (size_t i = 0; i < Z_STRLEN_P(value); i++) { if ((str[i] >= 127) && (flags & FILTER_FLAG_STRIP_HIGH)) { } else if ((str[i] < 32) && (flags & FILTER_FLAG_STRIP_LOW)) { } else if ((str[i] == '`') && (flags & FILTER_FLAG_STRIP_BACKTICK)) { @@ -143,9 +142,9 @@ static void filter_map_update(filter_map *map, int flag, const unsigned char *al } } -static void filter_map_apply(zval *value, filter_map *map) +static void filter_map_apply(zval *value, const filter_map *map) { - unsigned char *str; + const unsigned char *str; size_t i, c; zend_string *buf; @@ -216,7 +215,7 @@ void php_filter_encoded(PHP_INPUT_FILTER_PARAM_DECL) /* apply strip_high and strip_low filters */ php_filter_strip(value, flags); /* urlencode */ - php_filter_encode_url(value, (unsigned char *)DEFAULT_URL_ENCODE, sizeof(DEFAULT_URL_ENCODE)-1, flags & FILTER_FLAG_ENCODE_HIGH, flags & FILTER_FLAG_ENCODE_LOW, 1); + php_filter_encode_url(value, (unsigned char *)DEFAULT_URL_ENCODE, sizeof(DEFAULT_URL_ENCODE)-1); } /* }}} */ diff --git a/ext/filter/tests/gh18309.phpt b/ext/filter/tests/gh18309.phpt new file mode 100644 index 0000000000000..b541f10883fe6 --- /dev/null +++ b/ext/filter/tests/gh18309.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-18309 (ipv6 filter integer overflow) +--EXTENSIONS-- +filter +--FILE-- + +--EXPECT-- +bool(false) diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index 3dc401a4bffbb..f37ee68617616 100644 --- a/ext/ftp/ftp.c +++ b/ext/ftp/ftp.c @@ -68,41 +68,37 @@ * it sends the string "cmd args\r\n" if args is non-null, or * "cmd\r\n" if args is null */ -static int ftp_putcmd( ftpbuf_t *ftp, - const char *cmd, - const size_t cmd_len, - const char *args, - const size_t args_len); +static bool ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, const char *args, const size_t args_len); /* wrapper around send/recv to handle timeouts */ -static int my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len); -static int my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len); -static int my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen); +static int my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len); +static int my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len); +static int my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen); /* reads a line the socket , returns true on success, false on error */ -static int ftp_readline(ftpbuf_t *ftp); +static bool ftp_readline(ftpbuf_t *ftp); /* reads an ftp response, returns true on success, false on error */ -static int ftp_getresp(ftpbuf_t *ftp); +static bool ftp_getresp(ftpbuf_t *ftp); /* sets the ftp transfer type */ -static int ftp_type(ftpbuf_t *ftp, ftptype_t type); +static bool ftp_type(ftpbuf_t *ftp, ftptype_t type); /* opens up a data stream */ -static databuf_t* ftp_getdata(ftpbuf_t *ftp); +static databuf_t* ftp_getdata(ftpbuf_t *ftp); /* accepts the data connection, returns updated data buffer */ -static databuf_t* data_accept(databuf_t *data, ftpbuf_t *ftp); +static databuf_t* data_accept(databuf_t *data, ftpbuf_t *ftp); /* closes the data connection, no-op if already closed */ -static void data_close(ftpbuf_t *ftp); +static void data_close(ftpbuf_t *ftp); /* generic file lister */ -static char** ftp_genlist(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, const char *path, const size_t path_len); +static char** ftp_genlist(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, const char *path, const size_t path_len); #ifdef HAVE_FTP_SSL /* shuts down a TLS/SSL connection */ -static void ftp_ssl_shutdown(ftpbuf_t *ftp, php_socket_t fd, SSL *ssl_handle); +static void ftp_ssl_shutdown(ftpbuf_t *ftp, php_socket_t fd, SSL *ssl_handle); #endif /* IP and port conversion box */ @@ -112,9 +108,7 @@ union ipbox { unsigned char c[8]; }; -/* {{{ ftp_open */ -ftpbuf_t* -ftp_open(const char *host, short port, zend_long timeout_sec) +ftpbuf_t* ftp_open(const char *host, short port, zend_long timeout_sec) { ftpbuf_t *ftp; socklen_t size; @@ -158,14 +152,11 @@ ftp_open(const char *host, short port, zend_long timeout_sec) efree(ftp); return NULL; } -/* }}} */ -/* {{{ ftp_close */ -ftpbuf_t* -ftp_close(ftpbuf_t *ftp) +void ftp_close(ftpbuf_t *ftp) { if (ftp == NULL) { - return NULL; + return; } #ifdef HAVE_FTP_SSL if (ftp->last_ssl_session) { @@ -186,13 +177,9 @@ ftp_close(ftpbuf_t *ftp) } ftp_gc(ftp); efree(ftp); - return NULL; } -/* }}} */ -/* {{{ ftp_gc */ -void -ftp_gc(ftpbuf_t *ftp) +void ftp_gc(ftpbuf_t *ftp) { if (ftp == NULL) { return; @@ -206,21 +193,18 @@ ftp_gc(ftpbuf_t *ftp) ftp->syst = NULL; } } -/* }}} */ -/* {{{ ftp_quit */ -int -ftp_quit(ftpbuf_t *ftp) +bool ftp_quit(ftpbuf_t *ftp) { if (ftp == NULL) { - return 0; + return false; } if (!ftp_putcmd(ftp, "QUIT", sizeof("QUIT")-1, NULL, (size_t) 0)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp != 221) { - return 0; + return false; } if (ftp->pwd) { @@ -228,9 +212,8 @@ ftp_quit(ftpbuf_t *ftp) ftp->pwd = NULL; } - return 1; + return true; } -/* }}} */ #ifdef HAVE_FTP_SSL static int ftp_ssl_new_session_cb(SSL *ssl, SSL_SESSION *sess) @@ -248,9 +231,7 @@ static int ftp_ssl_new_session_cb(SSL *ssl, SSL_SESSION *sess) } #endif -/* {{{ ftp_login */ -int -ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pass, const size_t pass_len) +bool ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pass, const size_t pass_len) { #ifdef HAVE_FTP_SSL SSL_CTX *ctx = NULL; @@ -259,28 +240,28 @@ ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pa bool retry; #endif if (ftp == NULL) { - return 0; + return false; } #ifdef HAVE_FTP_SSL if (ftp->use_ssl && !ftp->ssl_active) { if (!ftp_putcmd(ftp, "AUTH", sizeof("AUTH")-1, "TLS", sizeof("TLS")-1)) { - return 0; + return false; } if (!ftp_getresp(ftp)) { - return 0; + return false; } if (ftp->resp != 234) { if (!ftp_putcmd(ftp, "AUTH", sizeof("AUTH")-1, "SSL", sizeof("SSL")-1)) { - return 0; + return false; } if (!ftp_getresp(ftp)) { - return 0; + return false; } if (ftp->resp != 334) { - return 0; + return false; } else { ftp->old_ssl = 1; ftp->use_ssl_for_data = 1; @@ -290,7 +271,7 @@ ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pa ctx = SSL_CTX_new(SSLv23_client_method()); if (ctx == NULL) { php_error_docref(NULL, E_WARNING, "Failed to create the SSL context"); - return 0; + return false; } ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; @@ -307,7 +288,7 @@ ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pa if (ftp->ssl_handle == NULL) { php_error_docref(NULL, E_WARNING, "Failed to create the SSL handle"); - return 0; + return false; } SSL_set_fd(ftp->ssl_handle, ftp->fd); @@ -319,11 +300,11 @@ ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pa /* TODO check if handling other error codes would make sense */ switch (err) { case SSL_ERROR_NONE: - retry = 0; + retry = false; break; case SSL_ERROR_ZERO_RETURN: - retry = 0; + retry = false; SSL_shutdown(ftp->ssl_handle); break; @@ -346,28 +327,28 @@ ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pa php_error_docref(NULL, E_WARNING, "SSL/TLS handshake failed"); SSL_shutdown(ftp->ssl_handle); SSL_free(ftp->ssl_handle); - return 0; + return false; } } while (retry); - ftp->ssl_active = 1; + ftp->ssl_active = true; if (!ftp->old_ssl) { /* set protection buffersize to zero */ if (!ftp_putcmd(ftp, "PBSZ", sizeof("PBSZ")-1, "0", sizeof("0")-1)) { - return 0; + return false; } if (!ftp_getresp(ftp)) { - return 0; + return false; } /* enable data conn encryption */ if (!ftp_putcmd(ftp, "PROT", sizeof("PROT")-1, "P", sizeof("P")-1)) { - return 0; + return false; } if (!ftp_getresp(ftp)) { - return 0; + return false; } ftp->use_ssl_for_data = (ftp->resp >= 200 && ftp->resp <=299); @@ -376,33 +357,30 @@ ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pa #endif if (!ftp_putcmd(ftp, "USER", sizeof("USER")-1, user, user_len)) { - return 0; + return false; } if (!ftp_getresp(ftp)) { - return 0; + return false; } if (ftp->resp == 230) { - return 1; + return true; } if (ftp->resp != 331) { - return 0; + return false; } if (!ftp_putcmd(ftp, "PASS", sizeof("PASS")-1, pass, pass_len)) { - return 0; + return false; } if (!ftp_getresp(ftp)) { - return 0; + return false; } return (ftp->resp == 230); } -/* }}} */ -/* {{{ ftp_reinit */ -int -ftp_reinit(ftpbuf_t *ftp) +bool ftp_reinit(ftpbuf_t *ftp) { if (ftp == NULL) { - return 0; + return false; } ftp_gc(ftp); @@ -410,19 +388,16 @@ ftp_reinit(ftpbuf_t *ftp) ftp->nb = 0; if (!ftp_putcmd(ftp, "REIN", sizeof("REIN")-1, NULL, (size_t) 0)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp != 220) { - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ ftp_syst */ -const char* -ftp_syst(ftpbuf_t *ftp) +const char* ftp_syst(ftpbuf_t *ftp) { char *syst, *end; @@ -453,11 +428,8 @@ ftp_syst(ftpbuf_t *ftp) } return ftp->syst; } -/* }}} */ -/* {{{ ftp_pwd */ -const char* -ftp_pwd(ftpbuf_t *ftp) +const char* ftp_pwd(ftpbuf_t *ftp) { char *pwd, *end; @@ -486,29 +458,23 @@ ftp_pwd(ftpbuf_t *ftp) return ftp->pwd; } -/* }}} */ -/* {{{ ftp_exec */ -int -ftp_exec(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len) +bool ftp_exec(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len) { if (ftp == NULL) { - return 0; + return false; } if (!ftp_putcmd(ftp, "SITE EXEC", sizeof("SITE EXEC")-1, cmd, cmd_len)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp != 200) { - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ ftp_raw */ -void -ftp_raw(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, zval *return_value) +void ftp_raw(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, zval *return_value) { if (ftp == NULL || cmd == NULL) { RETURN_NULL(); @@ -524,14 +490,11 @@ ftp_raw(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, zval *return_value } } } -/* }}} */ -/* {{{ ftp_chdir */ -int -ftp_chdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len) +bool ftp_chdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len) { if (ftp == NULL) { - return 0; + return false; } if (ftp->pwd) { @@ -540,21 +503,18 @@ ftp_chdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len) } if (!ftp_putcmd(ftp, "CWD", sizeof("CWD")-1, dir, dir_len)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp != 250) { - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ ftp_cdup */ -int -ftp_cdup(ftpbuf_t *ftp) +bool ftp_cdup(ftpbuf_t *ftp) { if (ftp == NULL) { - return 0; + return false; } if (ftp->pwd) { @@ -563,18 +523,15 @@ ftp_cdup(ftpbuf_t *ftp) } if (!ftp_putcmd(ftp, "CDUP", sizeof("CDUP")-1, NULL, (size_t) 0)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp != 250) { - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ ftp_mkdir */ -zend_string* -ftp_mkdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len) +zend_string* ftp_mkdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len) { char *mkd, *end; zend_string *ret; @@ -601,80 +558,71 @@ ftp_mkdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len) return ret; } -/* }}} */ -/* {{{ ftp_rmdir */ -int -ftp_rmdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len) +bool ftp_rmdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len) { if (ftp == NULL) { - return 0; + return false; } if (!ftp_putcmd(ftp, "RMD", sizeof("RMD")-1, dir, dir_len)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp != 250) { - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ ftp_chmod */ -int -ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const int filename_len) +bool ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const size_t filename_len) { char *buffer; size_t buffer_len; - if (ftp == NULL || filename_len <= 0) { - return 0; + if (ftp == NULL || filename_len == 0) { + return false; } buffer_len = spprintf(&buffer, 0, "CHMOD %o %s", mode, filename); if (!buffer) { - return 0; + return false; } if (!ftp_putcmd(ftp, "SITE", sizeof("SITE")-1, buffer, buffer_len)) { efree(buffer); - return 0; + return false; } efree(buffer); if (!ftp_getresp(ftp) || ftp->resp != 200) { - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ ftp_alloc */ -int -ftp_alloc(ftpbuf_t *ftp, const zend_long size, zend_string **response) +bool ftp_alloc(ftpbuf_t *ftp, const zend_long size, zend_string **response) { char buffer[64]; int buffer_len; if (ftp == NULL || size <= 0) { - return 0; + return false; } buffer_len = snprintf(buffer, sizeof(buffer) - 1, ZEND_LONG_FMT, size); if (buffer_len < 0) { - return 0; + return false; } if (!ftp_putcmd(ftp, "ALLO", sizeof("ALLO")-1, buffer, buffer_len)) { - return 0; + return false; } if (!ftp_getresp(ftp)) { - return 0; + return false; } if (response) { @@ -682,41 +630,29 @@ ftp_alloc(ftpbuf_t *ftp, const zend_long size, zend_string **response) } if (ftp->resp < 200 || ftp->resp >= 300) { - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ ftp_nlist */ -char** -ftp_nlist(ftpbuf_t *ftp, const char *path, const size_t path_len) +char** ftp_nlist(ftpbuf_t *ftp, const char *path, const size_t path_len) { return ftp_genlist(ftp, "NLST", sizeof("NLST")-1, path, path_len); } -/* }}} */ -/* {{{ ftp_list */ -char** -ftp_list(ftpbuf_t *ftp, const char *path, const size_t path_len, int recursive) +char** ftp_list(ftpbuf_t *ftp, const char *path, const size_t path_len, int recursive) { return ftp_genlist(ftp, ((recursive) ? "LIST -R" : "LIST"), ((recursive) ? sizeof("LIST -R")-1 : sizeof("LIST")-1), path, path_len); } -/* }}} */ -/* {{{ ftp_mlsd */ -char** -ftp_mlsd(ftpbuf_t *ftp, const char *path, const size_t path_len) +char** ftp_mlsd(ftpbuf_t *ftp, const char *path, const size_t path_len) { return ftp_genlist(ftp, "MLSD", sizeof("MLSD")-1, path, path_len); } -/* }}} */ - -/* {{{ ftp_mlsd_parse_line */ -int -ftp_mlsd_parse_line(HashTable *ht, const char *input) { +zend_result ftp_mlsd_parse_line(HashTable *ht, const char *input) +{ zval zstr; const char *end = input + strlen(input); @@ -755,42 +691,36 @@ ftp_mlsd_parse_line(HashTable *ht, const char *input) { return SUCCESS; } -/* }}} */ -/* {{{ ftp_type */ -int -ftp_type(ftpbuf_t *ftp, ftptype_t type) +static bool ftp_type(ftpbuf_t *ftp, ftptype_t type) { const char *typechar; if (ftp == NULL) { - return 0; + return false; } if (type == ftp->type) { - return 1; + return true; } if (type == FTPTYPE_ASCII) { typechar = "A"; } else if (type == FTPTYPE_IMAGE) { typechar = "I"; } else { - return 0; + return false; } if (!ftp_putcmd(ftp, "TYPE", sizeof("TYPE")-1, typechar, 1)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp != 200) { - return 0; + return false; } ftp->type = type; - return 1; + return true; } -/* }}} */ -/* {{{ ftp_pasv */ -int -ftp_pasv(ftpbuf_t *ftp, int pasv) +bool ftp_pasv(ftpbuf_t *ftp, int pasv) { char *ptr; union ipbox ipbox; @@ -800,21 +730,21 @@ ftp_pasv(ftpbuf_t *ftp, int pasv) struct sockaddr_in *sin; if (ftp == NULL) { - return 0; + return false; } if (pasv && ftp->pasv == 2) { - return 1; + return true; } ftp->pasv = 0; if (!pasv) { - return 1; + return true; } n = sizeof(ftp->pasvaddr); memset(&ftp->pasvaddr, 0, n); sa = (struct sockaddr *) &ftp->pasvaddr; if (getpeername(ftp->fd, sa, &n) < 0) { - return 0; + return false; } #ifdef HAVE_IPV6 @@ -824,16 +754,16 @@ ftp_pasv(ftpbuf_t *ftp, int pasv) /* try EPSV first */ if (!ftp_putcmd(ftp, "EPSV", sizeof("EPSV")-1, NULL, (size_t) 0)) { - return 0; + return false; } if (!ftp_getresp(ftp)) { - return 0; + return false; } if (ftp->resp == 229) { /* parse out the port */ for (ptr = ftp->inbuf; *ptr && *ptr != '('; ptr++); if (!*ptr) { - return 0; + return false; } delimiter = *++ptr; for (n = 0; *ptr && n < 3; ptr++) { @@ -844,10 +774,10 @@ ftp_pasv(ftpbuf_t *ftp, int pasv) sin6->sin6_port = htons((unsigned short) strtoul(ptr, &endptr, 10)); if (ptr == endptr || *endptr != delimiter) { - return 0; + return false; } ftp->pasv = 2; - return 1; + return true; } } @@ -855,16 +785,16 @@ ftp_pasv(ftpbuf_t *ftp, int pasv) #endif if (!ftp_putcmd(ftp, "PASV", sizeof("PASV")-1, NULL, (size_t) 0)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp != 227) { - return 0; + return false; } /* parse out the IP and port */ for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++); n = sscanf(ptr, "%lu,%lu,%lu,%lu,%lu,%lu", &b[0], &b[1], &b[2], &b[3], &b[4], &b[5]); if (n != 6) { - return 0; + return false; } for (n = 0; n < 6; n++) { ipbox.c[n] = (unsigned char) b[n]; @@ -877,20 +807,17 @@ ftp_pasv(ftpbuf_t *ftp, int pasv) ftp->pasv = 2; - return 1; + return true; } -/* }}} */ -/* {{{ ftp_get */ -int -ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos) +bool ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos) { databuf_t *data = NULL; size_t rcvd; char arg[MAX_LENGTH_OF_LONG]; if (ftp == NULL) { - return 0; + return false; } if (!ftp_type(ftp, type)) { goto bail; @@ -967,12 +894,11 @@ ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t pat goto bail; } - return 1; + return true; bail: data_close(ftp); - return 0; + return false; } -/* }}} */ static zend_result ftp_send_stream_to_data_socket(ftpbuf_t *ftp, databuf_t *data, php_stream *instream, ftptype_t type, bool send_once_and_return) { @@ -1047,15 +973,13 @@ static zend_result ftp_send_stream_to_data_socket(ftpbuf_t *ftp, databuf_t *data return SUCCESS; } -/* {{{ ftp_put */ -int -ftp_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos) +bool ftp_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos) { databuf_t *data = NULL; char arg[MAX_LENGTH_OF_LONG]; if (ftp == NULL) { - return 0; + return false; } if (!ftp_type(ftp, type)) { goto bail; @@ -1097,22 +1021,18 @@ ftp_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *inst if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) { goto bail; } - return 1; + return true; bail: data_close(ftp); - return 0; + return false; } -/* }}} */ - -/* {{{ ftp_append */ -int -ftp_append(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type) +bool ftp_append(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type) { - databuf_t *data = NULL; + databuf_t *data = NULL; if (ftp == NULL) { - return 0; + return false; } if (!ftp_type(ftp, type)) { goto bail; @@ -1141,16 +1061,13 @@ ftp_append(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *i if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) { goto bail; } - return 1; + return true; bail: data_close(ftp); - return 0; + return false; } -/* }}} */ -/* {{{ ftp_size */ -zend_long -ftp_size(ftpbuf_t *ftp, const char *path, const size_t path_len) +zend_long ftp_size(ftpbuf_t *ftp, const char *path, const size_t path_len) { if (ftp == NULL) { return -1; @@ -1166,11 +1083,8 @@ ftp_size(ftpbuf_t *ftp, const char *path, const size_t path_len) } return ZEND_ATOL(ftp->inbuf); } -/* }}} */ -/* {{{ ftp_mdtm */ -time_t -ftp_mdtm(ftpbuf_t *ftp, const char *path, const size_t path_len) +time_t ftp_mdtm(ftpbuf_t *ftp, const char *path, const size_t path_len) { time_t stamp; struct tm *gmt, tmbuf; @@ -1213,116 +1127,97 @@ ftp_mdtm(ftpbuf_t *ftp, const char *path, const size_t path_len) return stamp; } -/* }}} */ -/* {{{ ftp_delete */ -int -ftp_delete(ftpbuf_t *ftp, const char *path, const size_t path_len) +bool ftp_delete(ftpbuf_t *ftp, const char *path, const size_t path_len) { if (ftp == NULL) { - return 0; + return false; } if (!ftp_putcmd(ftp, "DELE", sizeof("DELE")-1, path, path_len)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp != 250) { - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ ftp_rename */ -int -ftp_rename(ftpbuf_t *ftp, const char *src, const size_t src_len, const char *dest, const size_t dest_len) +bool ftp_rename(ftpbuf_t *ftp, const char *src, const size_t src_len, const char *dest, const size_t dest_len) { if (ftp == NULL) { - return 0; + return false; } if (!ftp_putcmd(ftp, "RNFR", sizeof("RNFR")-1, src, src_len)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp != 350) { - return 0; + return false; } if (!ftp_putcmd(ftp, "RNTO", sizeof("RNTO")-1, dest, dest_len)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp != 250) { - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ ftp_site */ -int -ftp_site(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len) +bool ftp_site(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len) { if (ftp == NULL) { - return 0; + return false; } if (!ftp_putcmd(ftp, "SITE", sizeof("SITE")-1, cmd, cmd_len)) { - return 0; + return false; } if (!ftp_getresp(ftp) || ftp->resp < 200 || ftp->resp >= 300) { - return 0; + return false; } - return 1; + return true; } -/* }}} */ - -/* static functions */ -/* {{{ ftp_putcmd */ -int -ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, const char *args, const size_t args_len) +static bool ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, const char *args, const size_t args_len) { - int size; - char *data; + int size; + char data[FTP_BUFSIZE]; if (strpbrk(cmd, "\r\n")) { - return 0; + return false; } /* build the output buffer */ if (args && args[0]) { /* "cmd args\r\n\0" */ if (cmd_len + args_len + 4 > FTP_BUFSIZE) { - return 0; + return false; } if (strpbrk(args, "\r\n")) { return 0; } - size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s %s\r\n", cmd, args); + size = slprintf(data, sizeof(data), "%s %s\r\n", cmd, args); } else { /* "cmd\r\n\0" */ if (cmd_len + 3 > FTP_BUFSIZE) { - return 0; + return false; } - size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s\r\n", cmd); + size = slprintf(data, sizeof(data), "%s\r\n", cmd); } - data = ftp->outbuf; - /* Clear the inbuf and extra-lines buffer */ ftp->inbuf[0] = '\0'; ftp->extra = NULL; if (my_send(ftp, ftp->fd, data, size) != size) { - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ ftp_readline */ -int -ftp_readline(ftpbuf_t *ftp) +static bool ftp_readline(ftpbuf_t *ftp) { - long size, rcvd; - char *data, *eol; + long size, rcvd; + char *data, *eol; /* shift the extra to the front */ size = FTP_BUFSIZE; @@ -1347,42 +1242,39 @@ ftp_readline(ftpbuf_t *ftp) if ((ftp->extralen = --rcvd) == 0) { ftp->extra = NULL; } - return 1; + return true; } else if (*eol == '\n') { *eol = 0; ftp->extra = eol + 1; if ((ftp->extralen = --rcvd) == 0) { ftp->extra = NULL; } - return 1; + return true; } } data = eol; if ((rcvd = my_recv(ftp, ftp->fd, data, size)) < 1) { *data = 0; - return 0; + return false; } } while (size); *data = 0; - return 0; + return false; } -/* }}} */ -/* {{{ ftp_getresp */ -int -ftp_getresp(ftpbuf_t *ftp) +static bool ftp_getresp(ftpbuf_t *ftp) { if (ftp == NULL) { - return 0; + return false; } ftp->resp = 0; while (1) { if (!ftp_readline(ftp)) { - return 0; + return false; } /* Break out when the end-tag is found */ @@ -1393,7 +1285,7 @@ ftp_getresp(ftpbuf_t *ftp) /* translate the tag */ if (!isdigit(ftp->inbuf[0]) || !isdigit(ftp->inbuf[1]) || !isdigit(ftp->inbuf[2])) { - return 0; + return false; } ftp->resp = 100 * (ftp->inbuf[0] - '0') + 10 * (ftp->inbuf[1] - '0') + (ftp->inbuf[2] - '0'); @@ -1403,9 +1295,8 @@ ftp_getresp(ftpbuf_t *ftp) if (ftp->extra) { ftp->extra -= 4; } - return 1; + return true; } -/* }}} */ static ssize_t my_send_wrapper_with_restart(php_socket_t fd, const void *buf, size_t size, int flags) { ssize_t n; @@ -1423,7 +1314,7 @@ static ssize_t my_recv_wrapper_with_restart(php_socket_t fd, void *buf, size_t s return n; } -int single_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t size) { +static int single_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t size) { #ifdef HAVE_FTP_SSL int err; bool retry = 0; @@ -1506,9 +1397,7 @@ static int my_poll(php_socket_t fd, int events, int timeout) { return n; } -/* {{{ my_send */ -int -my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len) +static int my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len) { zend_long size, sent; int n; @@ -1541,13 +1430,10 @@ my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len) return len; } -/* }}} */ -/* {{{ my_recv */ -int -my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len) +static int my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len) { - int n, nr_bytes; + int n, nr_bytes; #ifdef HAVE_FTP_SSL int err; bool retry = 0; @@ -1620,13 +1506,10 @@ my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len) #endif return (nr_bytes); } -/* }}} */ -/* {{{ data_available */ -int -data_available(ftpbuf_t *ftp, php_socket_t s) +static bool data_available(ftpbuf_t *ftp, php_socket_t s) { - int n; + int n; n = my_poll(s, PHP_POLLREADABLE, 1000); if (n < 1) { @@ -1639,17 +1522,15 @@ data_available(ftpbuf_t *ftp, php_socket_t s) #endif } php_error_docref(NULL, E_WARNING, "%s", php_socket_strerror(errno, buf, sizeof buf)); - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ data_writeable */ -int -data_writeable(ftpbuf_t *ftp, php_socket_t s) + +static bool data_writeable(ftpbuf_t *ftp, php_socket_t s) { - int n; + int n; n = my_poll(s, POLLOUT, 1000); if (n < 1) { @@ -1662,18 +1543,15 @@ data_writeable(ftpbuf_t *ftp, php_socket_t s) #endif } php_error_docref(NULL, E_WARNING, "%s", php_socket_strerror(errno, buf, sizeof buf)); - return 0; + return false; } - return 1; + return true; } -/* }}} */ -/* {{{ my_accept */ -int -my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen) +static int my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen) { - int n; + int n; n = my_poll(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000); if (n < 1) { @@ -1691,11 +1569,8 @@ my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrl return accept(s, addr, addrlen); } -/* }}} */ -/* {{{ ftp_getdata */ -databuf_t* -ftp_getdata(ftpbuf_t *ftp) +static databuf_t* ftp_getdata(ftpbuf_t *ftp) { int fd = -1; databuf_t *data; @@ -1824,14 +1699,11 @@ ftp_getdata(ftpbuf_t *ftp) efree(data); return NULL; } -/* }}} */ -/* {{{ data_accept */ -databuf_t* -data_accept(databuf_t *data, ftpbuf_t *ftp) +static databuf_t* data_accept(databuf_t *data, ftpbuf_t *ftp) { php_sockaddr_storage addr; - socklen_t size; + socklen_t size; #ifdef HAVE_FTP_SSL SSL_CTX *ctx; @@ -1937,9 +1809,7 @@ data_accept(databuf_t *data, ftpbuf_t *ftp) return data; } -/* }}} */ -/* {{{ ftp_ssl_shutdown */ #ifdef HAVE_FTP_SSL static void ftp_ssl_shutdown(ftpbuf_t *ftp, php_socket_t fd, SSL *ssl_handle) { /* In TLS 1.3 it's common to receive session tickets after the handshake has completed. We need to train @@ -2000,10 +1870,8 @@ static void ftp_ssl_shutdown(ftpbuf_t *ftp, php_socket_t fd, SSL *ssl_handle) { (void)SSL_free(ssl_handle); } #endif -/* }}} */ -/* {{{ data_close */ -void data_close(ftpbuf_t *ftp) +static void data_close(ftpbuf_t *ftp) { ZEND_ASSERT(ftp != NULL); databuf_t *data = ftp->data; @@ -2033,11 +1901,8 @@ void data_close(ftpbuf_t *ftp) ftp->data = NULL; efree(data); } -/* }}} */ -/* {{{ ftp_genlist */ -char** -ftp_genlist(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, const char *path, const size_t path_len) +static char** ftp_genlist(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, const char *path, const size_t path_len) { php_stream *tmpstream = NULL; databuf_t *data = NULL; @@ -2137,14 +2002,11 @@ ftp_genlist(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, const char *pa efree(ret); return NULL; } -/* }}} */ -/* {{{ ftp_nb_get */ -int -ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos) +int ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos) { - databuf_t *data = NULL; - char arg[MAX_LENGTH_OF_LONG]; + databuf_t *data = NULL; + char arg[MAX_LENGTH_OF_LONG]; if (ftp == NULL) { return PHP_FTP_FAILED; @@ -2203,11 +2065,8 @@ ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t data_close(ftp); return PHP_FTP_FAILED; } -/* }}} */ -/* {{{ ftp_nb_continue_read */ -int -ftp_nb_continue_read(ftpbuf_t *ftp) +int ftp_nb_continue_read(ftpbuf_t *ftp) { databuf_t *data = NULL; char *ptr; @@ -2265,11 +2124,8 @@ ftp_nb_continue_read(ftpbuf_t *ftp) data_close(ftp); return PHP_FTP_FAILED; } -/* }}} */ -/* {{{ ftp_nb_put */ -int -ftp_nb_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos) +int ftp_nb_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos) { databuf_t *data = NULL; char arg[MAX_LENGTH_OF_LONG]; @@ -2317,12 +2173,8 @@ ftp_nb_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *i data_close(ftp); return PHP_FTP_FAILED; } -/* }}} */ - -/* {{{ ftp_nb_continue_write */ -int -ftp_nb_continue_write(ftpbuf_t *ftp) +int ftp_nb_continue_write(ftpbuf_t *ftp) { /* check if we can write more data */ if (!data_writeable(ftp, ftp->data->fd)) { @@ -2349,4 +2201,3 @@ ftp_nb_continue_write(ftpbuf_t *ftp) ftp->nb = 0; return PHP_FTP_FAILED; } -/* }}} */ diff --git a/ext/ftp/ftp.h b/ext/ftp/ftp.h index 94abc588ca857..241f92f57ec35 100644 --- a/ext/ftp/ftp.h +++ b/ext/ftp/ftp.h @@ -60,7 +60,6 @@ typedef struct ftpbuf char inbuf[FTP_BUFSIZE]; /* last response text */ char *extra; /* extra characters */ int extralen; /* number of extra chars */ - char outbuf[FTP_BUFSIZE]; /* command output buffer */ char *pwd; /* cached pwd */ char *syst; /* cached system type */ ftptype_t type; /* current transfer type */ @@ -92,42 +91,42 @@ typedef struct ftpbuf /* open a FTP connection, returns ftpbuf (NULL on error) * port is the ftp port in network byte order, or 0 for the default */ -ftpbuf_t* ftp_open(const char *host, short port, zend_long timeout_sec); +ftpbuf_t* ftp_open(const char *host, short port, zend_long timeout_sec); /* quits from the ftp session (it still needs to be closed) * return true on success, false on error */ -int ftp_quit(ftpbuf_t *ftp); +bool ftp_quit(ftpbuf_t *ftp); /* frees up any cached data held in the ftp buffer */ -void ftp_gc(ftpbuf_t *ftp); +void ftp_gc(ftpbuf_t *ftp); /* close the FTP connection and return NULL */ -ftpbuf_t* ftp_close(ftpbuf_t *ftp); +void ftp_close(ftpbuf_t *ftp); /* logs into the FTP server, returns true on success, false on error */ -int ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pass, const size_t pass_len); +bool ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pass, const size_t pass_len); /* reinitializes the connection, returns true on success, false on error */ -int ftp_reinit(ftpbuf_t *ftp); +bool ftp_reinit(ftpbuf_t *ftp); /* returns the remote system type (NULL on error) */ -const char* ftp_syst(ftpbuf_t *ftp); +const char* ftp_syst(ftpbuf_t *ftp); /* returns the present working directory (NULL on error) */ -const char* ftp_pwd(ftpbuf_t *ftp); +const char* ftp_pwd(ftpbuf_t *ftp); /* exec a command [special features], return true on success, false on error */ -int ftp_exec(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len); +bool ftp_exec(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len); /* send a raw ftp command, return response as a hashtable, NULL on error */ -void ftp_raw(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, zval *return_value); +void ftp_raw(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, zval *return_value); /* changes directories, return true on success, false on error */ -int ftp_chdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len); +bool ftp_chdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len); /* changes to parent directory, return true on success, false on error */ -int ftp_cdup(ftpbuf_t *ftp); +bool ftp_cdup(ftpbuf_t *ftp); /* creates a directory, return the directory name on success, NULL on error. * the return value must be freed @@ -135,95 +134,94 @@ int ftp_cdup(ftpbuf_t *ftp); zend_string* ftp_mkdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len); /* removes a directory, return true on success, false on error */ -int ftp_rmdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len); +bool ftp_rmdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len); /* Set permissions on a file */ -int ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const int filename_len); +bool ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const size_t filename_len); /* Allocate space on remote server with ALLO command * Many servers will respond with 202 Allocation not necessary, * however some servers will not accept STOR or APPE until ALLO is confirmed. * If response is passed, it is estrdup()ed from ftp->inbuf and must be freed * or assigned to a zval returned to the user */ -int ftp_alloc(ftpbuf_t *ftp, const zend_long size, zend_string **response); +bool ftp_alloc(ftpbuf_t *ftp, const zend_long size, zend_string **response); /* returns a NULL-terminated array of filenames in the given path * or NULL on error. the return array must be freed (but don't * free the array elements) */ -char** ftp_nlist(ftpbuf_t *ftp, const char *path, const size_t path_len); +char** ftp_nlist(ftpbuf_t *ftp, const char *path, const size_t path_len); /* returns a NULL-terminated array of lines returned by the ftp * LIST command for the given path or NULL on error. the return * array must be freed (but don't * free the array elements) */ -char** ftp_list(ftpbuf_t *ftp, const char *path, const size_t path_len, int recursive); +char** ftp_list(ftpbuf_t *ftp, const char *path, const size_t path_len, int recursive); /* populates a hashtable with the facts contained in one line of * an MLSD response. */ -int ftp_mlsd_parse_line(HashTable *ht, const char *input); +zend_result ftp_mlsd_parse_line(HashTable *ht, const char *input); /* returns a NULL-terminated array of lines returned by the ftp * MLSD command for the given path or NULL on error. the return * array must be freed (but don't * free the array elements) */ -char** ftp_mlsd(ftpbuf_t *ftp, const char *path, const size_t path_len); +char** ftp_mlsd(ftpbuf_t *ftp, const char *path, const size_t path_len); /* switches passive mode on or off * returns true on success, false on error */ -int ftp_pasv(ftpbuf_t *ftp, int pasv); +bool ftp_pasv(ftpbuf_t *ftp, int pasv); /* retrieves a file and saves its contents to outfp * returns true on success, false on error */ -int ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos); +bool ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos); /* stores the data from a file, socket, or process as a file on the remote server * returns true on success, false on error */ -int ftp_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos); +bool ftp_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos); /* append the data from a file, socket, or process as a file on the remote server * returns true on success, false on error */ -int ftp_append(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type); +bool ftp_append(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type); /* returns the size of the given file, or -1 on error */ -zend_long ftp_size(ftpbuf_t *ftp, const char *path, const size_t path_len); +zend_long ftp_size(ftpbuf_t *ftp, const char *path, const size_t path_len); /* returns the last modified time of the given file, or -1 on error */ -time_t ftp_mdtm(ftpbuf_t *ftp, const char *path, const size_t path_len); +time_t ftp_mdtm(ftpbuf_t *ftp, const char *path, const size_t path_len); /* renames a file on the server */ -int ftp_rename(ftpbuf_t *ftp, const char *src, const size_t src_len, const char *dest, const size_t dest_len); +bool ftp_rename(ftpbuf_t *ftp, const char *src, const size_t src_len, const char *dest, const size_t dest_len); /* deletes the file from the server */ -int ftp_delete(ftpbuf_t *ftp, const char *path, const size_t path_len); +bool ftp_delete(ftpbuf_t *ftp, const char *path, const size_t path_len); /* sends a SITE command to the server */ -int ftp_site(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len); +bool ftp_site(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len); /* retrieves part of a file and saves its contents to outfp * returns true on success, false on error */ -int ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos); +int ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos); /* stores the data from a file, socket, or process as a file on the remote server * returns true on success, false on error */ -int ftp_nb_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos); +int ftp_nb_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos); /* continues a previous nb_(f)get command */ -int ftp_nb_continue_read(ftpbuf_t *ftp); +int ftp_nb_continue_read(ftpbuf_t *ftp); /* continues a previous nb_(f)put command */ -int ftp_nb_continue_write(ftpbuf_t *ftp); - +int ftp_nb_continue_write(ftpbuf_t *ftp); #endif diff --git a/ext/ftp/ftp.stub.php b/ext/ftp/ftp.stub.php index beab97f2d98e4..6560dd8930186 100644 --- a/ext/ftp/ftp.stub.php +++ b/ext/ftp/ftp.stub.php @@ -132,7 +132,7 @@ function ftp_close(FTP\Connection $ftp): bool {} function ftp_quit(FTP\Connection $ftp): bool {} /** @param int|bool $value */ - function ftp_set_option(FTP\Connection $ftp, int $option, $value): bool {} + function ftp_set_option(FTP\Connection $ftp, int $option, $value): true {} function ftp_get_option(FTP\Connection $ftp, int $option): int|bool {} } diff --git a/ext/ftp/ftp_arginfo.h b/ext/ftp/ftp_arginfo.h index e28a549f9d670..77bc47df03f69 100644 --- a/ext/ftp/ftp_arginfo.h +++ b/ext/ftp/ftp_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 072486274a3361dee3655cfd046a293cfb8a2757 */ + * Stub hash: 29606d7114a0698b8ae231173a624b17c196ffec */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_ftp_connect, 0, 1, FTP\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, hostname, IS_STRING, 0) @@ -182,7 +182,7 @@ ZEND_END_ARG_INFO() #define arginfo_ftp_quit arginfo_ftp_cdup -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ftp_set_option, 0, 3, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ftp_set_option, 0, 3, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, ftp, FTP\\Connection, 0) ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0) ZEND_ARG_INFO(0, value) diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c index 17dc94b728eba..fb771a66d73e4 100644 --- a/ext/ftp/php_ftp.c +++ b/ext/ftp/php_ftp.c @@ -162,7 +162,7 @@ PHP_FUNCTION(ftp_connect) ftp->usepasvaddress = FTP_DEFAULT_USEPASVADDRESS; #ifdef HAVE_FTP_SSL /* disable ssl */ - ftp->use_ssl = 0; + ftp->use_ssl = false; #endif object_init_ex(return_value, php_ftp_ce); @@ -198,7 +198,7 @@ PHP_FUNCTION(ftp_ssl_connect) ftp->autoseek = FTP_DEFAULT_AUTOSEEK; ftp->usepasvaddress = FTP_DEFAULT_USEPASVADDRESS; /* enable ssl */ - ftp->use_ssl = 1; + ftp->use_ssl = true; object_init_ex(return_value, php_ftp_ce); ftp_object_from_zend_object(Z_OBJ_P(return_value))->ftp = ftp; @@ -390,7 +390,7 @@ PHP_FUNCTION(ftp_rmdir) } GET_FTPBUF(ftp, z_ftp); - /* remove directorie */ + /* remove directories */ if (!ftp_rmdir(ftp, dir, dir_len)) { if (*ftp->inbuf) { php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf); @@ -432,7 +432,7 @@ PHP_FUNCTION(ftp_alloc) { zval *z_ftp, *zresponse = NULL; ftpbuf_t *ftp; - zend_long size, ret; + zend_long size; zend_string *response = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol|z", &z_ftp, php_ftp_ce, &size, &zresponse) == FAILURE) { @@ -440,17 +440,13 @@ PHP_FUNCTION(ftp_alloc) } GET_FTPBUF(ftp, z_ftp); - ret = ftp_alloc(ftp, size, zresponse ? &response : NULL); + bool ret = ftp_alloc(ftp, size, zresponse ? &response : NULL); if (response) { ZEND_TRY_ASSIGN_REF_STR(zresponse, response); } - if (!ret) { - RETURN_FALSE; - } - - RETURN_TRUE; + RETURN_BOOL(ret); } /* }}} */ @@ -797,8 +793,8 @@ PHP_FUNCTION(ftp_nb_get) } /* configuration */ - ftp->direction = 0; /* recv */ - ftp->closestream = 1; /* do close */ + ftp->direction = false; /* recv */ + ftp->closestream = true; /* do close */ if ((ret = ftp_nb_get(ftp, outstream, remote, remote_len, xtype, resumepos)) == PHP_FTP_FAILED) { php_stream_close(outstream); @@ -950,8 +946,8 @@ PHP_FUNCTION(ftp_nb_fput) } /* configuration */ - ftp->direction = 1; /* send */ - ftp->closestream = 0; /* do not close */ + ftp->direction = true; /* send */ + ftp->closestream = false; /* do not close */ if (((ret = ftp_nb_put(ftp, remote, remote_len, stream, xtype, startpos)) == PHP_FTP_FAILED)) { if (*ftp->inbuf) { @@ -1091,8 +1087,8 @@ PHP_FUNCTION(ftp_nb_put) } /* configuration */ - ftp->direction = 1; /* send */ - ftp->closestream = 1; /* do close */ + ftp->direction = true; /* send */ + ftp->closestream = true; /* do close */ ret = ftp_nb_put(ftp, remote, remote_len, instream, xtype, startpos); diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 0bbf077a52500..e993fb65f47d0 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -27,7 +27,6 @@ #include "php.h" #include "php_ini.h" -#include "ext/standard/head.h" #include #include "SAPI.h" #include "php_gd.h" @@ -649,7 +648,7 @@ PHP_FUNCTION(imagesetstyle) } /* copy the style values in the stylearr */ - stylearr = safe_emalloc(sizeof(int), num_styles, 0); + stylearr = safe_emalloc(num_styles, sizeof(int), 0); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(styles), item) { stylearr[index++] = zval_get_long(item); @@ -752,11 +751,7 @@ PHP_FUNCTION(imagepalettetotruecolor) im = php_gd_libgdimageptr_from_zval_p(IM); - if (gdImagePaletteToTrueColor(im) == 0) { - RETURN_FALSE; - } - - RETURN_TRUE; + RETURN_BOOL(gdImagePaletteToTrueColor(im) != 0); } /* }}} */ @@ -1754,7 +1749,6 @@ static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, cons char *file = NULL; zend_long quality = 128, type = 1; gdImagePtr im; - FILE *fp; size_t file_len = 0; /* The quality parameter for gd2 stands for chunk size */ @@ -1784,7 +1778,7 @@ static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, cons if (file_len) { PHP_GD_CHECK_OPEN_BASEDIR(file, "Invalid filename"); - fp = VCWD_FOPEN(file, "wb"); + FILE *fp = VCWD_FOPEN(file, "wb"); if (!fp) { php_error_docref(NULL, E_WARNING, "Unable to open \"%s\" for writing", file); RETURN_FALSE; @@ -1852,9 +1846,7 @@ PHP_FUNCTION(imagexbm) zend_long foreground_color; bool foreground_color_is_null = true; gdImagePtr im; - int i; gdIOCtx *ctx = NULL; - php_stream *stream; ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_OBJECT_OF_CLASS(imgind, gd_image_ce) @@ -1866,7 +1858,7 @@ PHP_FUNCTION(imagexbm) im = php_gd_libgdimageptr_from_zval_p(imgind); if (file != NULL) { - stream = php_stream_open_wrapper(file, "wb", REPORT_ERRORS|IGNORE_PATH, NULL); + php_stream *stream = php_stream_open_wrapper(file, "wb", REPORT_ERRORS|IGNORE_PATH, NULL); if (stream == NULL) { RETURN_FALSE; } @@ -1877,6 +1869,7 @@ PHP_FUNCTION(imagexbm) } if (foreground_color_is_null) { + int i; for (i = 0; i < gdImageColorsTotal(im); i++) { if (!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) { break; @@ -2084,7 +2077,6 @@ PHP_FUNCTION(imagewbmp) zend_long foreground_color; bool foreground_color_is_null = true; gdImagePtr im; - int i; gdIOCtx *ctx; zval *to_zval = NULL; @@ -2103,6 +2095,7 @@ PHP_FUNCTION(imagewbmp) } if (foreground_color_is_null) { + int i; for (i = 0; i < gdImageColorsTotal(im); i++) { if (!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) { break; @@ -2445,7 +2438,7 @@ PHP_FUNCTION(imagecolorsforindex) col = index; if ((col >= 0 && gdImageTrueColor(im)) || (!gdImageTrueColor(im) && col >= 0 && col < gdImageColorsTotal(im))) { - array_init(return_value); + array_init_size(return_value, 4); add_assoc_long(return_value,"red", gdImageRed(im,col)); add_assoc_long(return_value,"green", gdImageGreen(im,col)); @@ -2463,7 +2456,6 @@ PHP_FUNCTION(imagegammacorrect) { zval *IM; gdImagePtr im; - int i; double input, output, gamma; ZEND_PARSE_PARAMETERS_START(3, 3) @@ -2487,11 +2479,9 @@ PHP_FUNCTION(imagegammacorrect) im = php_gd_libgdimageptr_from_zval_p(IM); if (gdImageTrueColor(im)) { - int x, y, c; - - for (y = 0; y < gdImageSY(im); y++) { - for (x = 0; x < gdImageSX(im); x++) { - c = gdImageGetPixel(im, x, y); + for (int y = 0; y < gdImageSY(im); y++) { + for (int x = 0; x < gdImageSX(im); x++) { + int c = gdImageGetPixel(im, x, y); gdImageSetPixel(im, x, y, gdTrueColorAlpha( (int) ((pow((gdTrueColorGetRed(c) / 255.0), gamma) * 255) + .5), @@ -2505,7 +2495,7 @@ PHP_FUNCTION(imagegammacorrect) RETURN_TRUE; } - for (i = 0; i < gdImageColorsTotal(im); i++) { + for (int i = 0; i < gdImageColorsTotal(im); i++) { im->red[i] = (int)((pow((im->red[i] / 255.0), gamma) * 255) + .5); im->green[i] = (int)((pow((im->green[i] / 255.0), gamma) * 255) + .5); im->blue[i] = (int)((pow((im->blue[i] / 255.0), gamma) * 255) + .5); @@ -2811,7 +2801,7 @@ static void php_imagepolygon(INTERNAL_FUNCTION_PARAMETERS, int filled) zval *var = NULL; gdImagePtr im; gdPointPtr points; - int npoints, col, nelem, i; + int npoints, col, nelem; ZEND_PARSE_PARAMETERS_START(3, 4) Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce) @@ -2851,7 +2841,7 @@ static void php_imagepolygon(INTERNAL_FUNCTION_PARAMETERS, int filled) points = (gdPointPtr) safe_emalloc(npoints, sizeof(gdPoint), 0); - for (i = 0; i < npoints; i++) { + for (int i = 0; i < npoints; i++) { if ((var = zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2))) != NULL) { points[i].x = zval_get_long(var); } @@ -3313,18 +3303,20 @@ PHP_FUNCTION(imagegetclip) gdImageGetClip(im, &x1, &y1, &x2, &y2); - array_init(return_value); - add_next_index_long(return_value, x1); - add_next_index_long(return_value, y1); - add_next_index_long(return_value, x2); - add_next_index_long(return_value, y2); + array_init_size(return_value, 4); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); + add_index_long(return_value, 0, x1); + add_index_long(return_value, 1, y1); + add_index_long(return_value, 2, x2); + add_index_long(return_value, 3, y2); } /* }}} */ +#ifdef HAVE_GD_FREETYPE + #define TTFTEXT_DRAW 0 #define TTFTEXT_BBOX 1 -#ifdef HAVE_GD_FREETYPE /* {{{ Give the bounding box of a text using fonts via freetype2 */ PHP_FUNCTION(imageftbbox) { @@ -3363,6 +3355,17 @@ static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int mode) im = php_gd_libgdimageptr_from_zval_p(IM); } + // FT_F26Dot6 is a signed long alias + if (ptsize < (double)LONG_MIN / 64 || ptsize > (double)LONG_MAX / 64) { + zend_argument_value_error(2, "must be between " ZEND_LONG_FMT " and " ZEND_LONG_FMT, (zend_long)((double)LONG_MIN / 64), (zend_long)((double)LONG_MAX / 64)); + RETURN_THROWS(); + } + + if (UNEXPECTED(!zend_finite(ptsize))) { + zend_argument_value_error(2, "must be finite"); + RETURN_THROWS(); + } + /* convert angle to radians */ angle = angle * (M_PI/180); @@ -3396,11 +3399,12 @@ static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int mode) RETURN_FALSE; } - array_init(return_value); + array_init_size(return_value, 8); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); /* return array with the text's bounding box */ for (i = 0; i < 8; i++) { - add_next_index_long(return_value, brect[i]); + add_index_long(return_value, i, brect[i]); } } /* }}} */ @@ -3419,22 +3423,14 @@ static void php_image_filter_negate(INTERNAL_FUNCTION_PARAMETERS) { PHP_GD_SINGLE_RES - if (gdImageNegate(im_src) == 1) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImageNegate(im_src) == 1); } static void php_image_filter_grayscale(INTERNAL_FUNCTION_PARAMETERS) { PHP_GD_SINGLE_RES - if (gdImageGrayScale(im_src) == 1) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImageGrayScale(im_src) == 1); } static void php_image_filter_brightness(INTERNAL_FUNCTION_PARAMETERS) @@ -3451,11 +3447,7 @@ static void php_image_filter_brightness(INTERNAL_FUNCTION_PARAMETERS) im_src = php_gd_libgdimageptr_from_zval_p(SIM); - if (gdImageBrightness(im_src, (int)brightness) == 1) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImageBrightness(im_src, (int)brightness) == 1); } static void php_image_filter_contrast(INTERNAL_FUNCTION_PARAMETERS) @@ -3472,11 +3464,7 @@ static void php_image_filter_contrast(INTERNAL_FUNCTION_PARAMETERS) im_src = php_gd_libgdimageptr_from_zval_p(SIM); - if (gdImageContrast(im_src, (int)contrast) == 1) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImageContrast(im_src, (int)contrast) == 1); } static void php_image_filter_colorize(INTERNAL_FUNCTION_PARAMETERS) @@ -3498,66 +3486,42 @@ static void php_image_filter_colorize(INTERNAL_FUNCTION_PARAMETERS) im_src = php_gd_libgdimageptr_from_zval_p(SIM); - if (gdImageColor(im_src, (int) r, (int) g, (int) b, (int) a) == 1) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImageColor(im_src, (int) r, (int) g, (int) b, (int) a) == 1); } static void php_image_filter_edgedetect(INTERNAL_FUNCTION_PARAMETERS) { PHP_GD_SINGLE_RES - if (gdImageEdgeDetectQuick(im_src) == 1) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImageEdgeDetectQuick(im_src) == 1); } static void php_image_filter_emboss(INTERNAL_FUNCTION_PARAMETERS) { PHP_GD_SINGLE_RES - if (gdImageEmboss(im_src) == 1) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImageEmboss(im_src) == 1); } static void php_image_filter_gaussian_blur(INTERNAL_FUNCTION_PARAMETERS) { PHP_GD_SINGLE_RES - if (gdImageGaussianBlur(im_src) == 1) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImageGaussianBlur(im_src) == 1); } static void php_image_filter_selective_blur(INTERNAL_FUNCTION_PARAMETERS) { PHP_GD_SINGLE_RES - if (gdImageSelectiveBlur(im_src) == 1) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImageSelectiveBlur(im_src) == 1); } static void php_image_filter_mean_removal(INTERNAL_FUNCTION_PARAMETERS) { PHP_GD_SINGLE_RES - if (gdImageMeanRemoval(im_src) == 1) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImageMeanRemoval(im_src) == 1); } static void php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS) @@ -3575,11 +3539,7 @@ static void php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS) im_src = php_gd_libgdimageptr_from_zval_p(SIM); - if (gdImageSmooth(im_src, (float)weight)==1) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImageSmooth(im_src, (float)weight) == 1); } static void php_image_filter_pixelate(INTERNAL_FUNCTION_PARAMETERS) @@ -3599,11 +3559,7 @@ static void php_image_filter_pixelate(INTERNAL_FUNCTION_PARAMETERS) im = php_gd_libgdimageptr_from_zval_p(IM); - if (gdImagePixelate(im, (int) blocksize, (const unsigned int) mode)) { - RETURN_TRUE; - } - - RETURN_FALSE; + RETURN_BOOL(gdImagePixelate(im, (int) blocksize, (const unsigned int) mode));; } static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS) @@ -3645,7 +3601,7 @@ static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS) RETURN_BOOL(gdImageScatter(im, (int)scatter_sub, (int)scatter_plus)); } - colors = emalloc(num_colors * sizeof(int)); + colors = safe_emalloc(num_colors, sizeof(int), 0); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(hash_colors), color) { *(colors + i++) = (int) zval_get_long(color); @@ -3702,7 +3658,6 @@ PHP_FUNCTION(imageconvolution) zval *var = NULL, *var2 = NULL; gdImagePtr im_src = NULL; double div, offset; - int nelem, i, j, res; float matrix[3][3] = {{0,0,0}, {0,0,0}, {0,0,0}}; ZEND_PARSE_PARAMETERS_START(4, 4) @@ -3714,20 +3669,19 @@ PHP_FUNCTION(imageconvolution) im_src = php_gd_libgdimageptr_from_zval_p(SIM); - nelem = zend_hash_num_elements(Z_ARRVAL_P(hash_matrix)); - if (nelem != 3) { + if (zend_hash_num_elements(Z_ARRVAL_P(hash_matrix)) != 3) { zend_argument_value_error(2, "must be a 3x3 array"); RETURN_THROWS(); } - for (i=0; i<3; i++) { - if ((var = zend_hash_index_find(Z_ARRVAL_P(hash_matrix), (i))) != NULL && Z_TYPE_P(var) == IS_ARRAY) { + for (uint8_t i = 0; i < 3; i++) { + if ((var = zend_hash_index_find_deref(Z_ARRVAL_P(hash_matrix), (i))) != NULL && Z_TYPE_P(var) == IS_ARRAY) { if (zend_hash_num_elements(Z_ARRVAL_P(var)) != 3 ) { zend_argument_value_error(2, "must be a 3x3 array, matrix[%d] only has %d elements", i, zend_hash_num_elements(Z_ARRVAL_P(var))); RETURN_THROWS(); } - for (j=0; j<3; j++) { + for (uint8_t j = 0; j < 3; j++) { if ((var2 = zend_hash_index_find(Z_ARRVAL_P(var), j)) != NULL) { matrix[i][j] = (float) zval_get_double(var2); } else { @@ -3754,13 +3708,7 @@ PHP_FUNCTION(imageconvolution) RETURN_THROWS(); } - res = gdImageConvolution(im_src, matrix, div_float, (float) offset); - - if (res) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(gdImageConvolution(im_src, matrix, div_float, (float) offset)); } /* }}} */ /* End section: Filters */ @@ -3867,6 +3815,26 @@ PHP_FUNCTION(imagecrop) RETURN_THROWS(); } + if ((rect.width > 0 && rect.x > INT_MAX - rect.width)) { + zend_argument_value_error(2, "overflow with \"x\" and \"width\" keys"); + RETURN_THROWS(); + } + + if ((rect.width < 0 && rect.x < INT_MIN - rect.width)) { + zend_argument_value_error(2, "underflow with \"x\" and \"width\" keys"); + RETURN_THROWS(); + } + + if ((rect.height > 0 && rect.y > INT_MAX - rect.height)) { + zend_argument_value_error(2, "overflow with \"y\" and \"height\" keys"); + RETURN_THROWS(); + } + + if ((rect.height < 0 && rect.y < INT_MIN - rect.height)) { + zend_argument_value_error(2, "underflow with \"y\" and \"height\" keys"); + RETURN_THROWS(); + } + im_crop = gdImageCrop(im, &rect); if (im_crop == NULL) { @@ -4013,10 +3981,7 @@ PHP_FUNCTION(imageaffine) gdRectPtr pRect = NULL; zval *z_rect = NULL; zval *z_affine; - zval *tmp; double affine[6]; - int i, nelems; - zval *zval_affine_elem = NULL; ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce) @@ -4027,14 +3992,15 @@ PHP_FUNCTION(imageaffine) src = php_gd_libgdimageptr_from_zval_p(IM); - - if ((nelems = zend_hash_num_elements(Z_ARRVAL_P(z_affine))) != 6) { + uint32_t nelems = zend_hash_num_elements(Z_ARRVAL_P(z_affine)); + if (nelems != 6) { zend_argument_value_error(2, "must have 6 elements"); RETURN_THROWS(); } - for (i = 0; i < nelems; i++) { - if ((zval_affine_elem = zend_hash_index_find(Z_ARRVAL_P(z_affine), i)) != NULL) { + for (uint32_t i = 0; i < nelems; i++) { + zval *zval_affine_elem = zend_hash_index_find_deref(Z_ARRVAL_P(z_affine), i); + if (zval_affine_elem != NULL) { switch (Z_TYPE_P(zval_affine_elem)) { case IS_LONG: case IS_DOUBLE: @@ -4053,6 +4019,7 @@ PHP_FUNCTION(imageaffine) } if (z_rect != NULL) { + zval *tmp; if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "x", sizeof("x") - 1)) != NULL) { rect.x = zval_get_long(tmp); } else { @@ -4102,7 +4069,7 @@ PHP_FUNCTION(imageaffinematrixget) zend_long type; zval *options = NULL; zval *tmp; - int res = GD_FALSE, i; + int res = GD_FALSE; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_LONG(type) @@ -4165,8 +4132,9 @@ PHP_FUNCTION(imageaffinematrixget) if (res == GD_FALSE) { RETURN_FALSE; } else { - array_init(return_value); - for (i = 0; i < 6; i++) { + array_init_size(return_value, 6); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); + for (uint8_t i = 0; i < 6; i++) { add_index_double(return_value, i, affine[i]); } } @@ -4200,7 +4168,7 @@ PHP_FUNCTION(imageaffinematrixconcat) } for (i = 0; i < 6; i++) { - if ((tmp = zend_hash_index_find(Z_ARRVAL_P(z_m1), i)) != NULL) { + if ((tmp = zend_hash_index_find_deref(Z_ARRVAL_P(z_m1), i)) != NULL) { switch (Z_TYPE_P(tmp)) { case IS_LONG: case IS_DOUBLE: @@ -4213,7 +4181,7 @@ PHP_FUNCTION(imageaffinematrixconcat) } } - if ((tmp = zend_hash_index_find(Z_ARRVAL_P(z_m2), i)) != NULL) { + if ((tmp = zend_hash_index_find_deref(Z_ARRVAL_P(z_m2), i)) != NULL) { switch (Z_TYPE_P(tmp)) { case IS_LONG: case IS_DOUBLE: @@ -4231,7 +4199,8 @@ PHP_FUNCTION(imageaffinematrixconcat) RETURN_FALSE; } - array_init(return_value); + array_init_size(return_value, 6); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for (i = 0; i < 6; i++) { add_index_double(return_value, i, mr[i]); } @@ -4323,9 +4292,10 @@ PHP_FUNCTION(imageresolution) RETURN_TRUE; } - array_init(return_value); - add_next_index_long(return_value, gdImageResolutionX(im)); - add_next_index_long(return_value, gdImageResolutionY(im)); + zval imx, imy; + ZVAL_LONG(&imx, gdImageResolutionX(im)); + ZVAL_LONG(&imy, gdImageResolutionY(im)); + RETURN_ARR(zend_new_pair(&imx, &imy)); } /* }}} */ diff --git a/ext/gd/gd.stub.php b/ext/gd/gd.stub.php index 347e43e728b87..b3b82766ee981 100644 --- a/ext/gd/gd.stub.php +++ b/ext/gd/gd.stub.php @@ -496,19 +496,19 @@ function imagetruecolortopalette(GdImage $image, bool $dither, int $num_colors): function imagepalettetotruecolor(GdImage $image): bool {} -function imagecolormatch(GdImage $image1, GdImage $image2): bool {} +function imagecolormatch(GdImage $image1, GdImage $image2): true {} -function imagesetthickness(GdImage $image, int $thickness): bool {} +function imagesetthickness(GdImage $image, int $thickness): true {} -function imagefilledellipse(GdImage $image, int $center_x, int $center_y, int $width, int $height, int $color): bool {} +function imagefilledellipse(GdImage $image, int $center_x, int $center_y, int $width, int $height, int $color): true {} -function imagefilledarc(GdImage $image, int $center_x, int $center_y, int $width, int $height, int $start_angle, int $end_angle, int $color, int $style): bool {} +function imagefilledarc(GdImage $image, int $center_x, int $center_y, int $width, int $height, int $start_angle, int $end_angle, int $color, int $style): true {} -function imagealphablending(GdImage $image, bool $enable): bool {} +function imagealphablending(GdImage $image, bool $enable): true {} -function imagesavealpha(GdImage $image, bool $enable): bool {} +function imagesavealpha(GdImage $image, bool $enable): true {} -function imagelayereffect(GdImage $image, int $effect): bool {} +function imagelayereffect(GdImage $image, int $effect): true {} function imagecolorallocatealpha(GdImage $image, int $red, int $green, int $blue, int $alpha): int|false {} @@ -518,7 +518,7 @@ function imagecolorclosestalpha(GdImage $image, int $red, int $green, int $blue, function imagecolorexactalpha(GdImage $image, int $red, int $green, int $blue, int $alpha): int {} -function imagecopyresampled(GdImage $dst_image, GdImage $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $dst_width, int $dst_height, int $src_width, int $src_height): bool {} +function imagecopyresampled(GdImage $dst_image, GdImage $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $dst_width, int $dst_height, int $src_width, int $src_height): true {} #ifdef PHP_WIN32 @@ -533,9 +533,9 @@ function imagegrabscreen(): GdImage|false {} /** @refcount 1 */ function imagerotate(GdImage $image, float $angle, int $background_color): GdImage|false {} -function imagesettile(GdImage $image, GdImage $tile): bool {} +function imagesettile(GdImage $image, GdImage $tile): true {} -function imagesetbrush(GdImage $image, GdImage $brush): bool {} +function imagesetbrush(GdImage $image, GdImage $brush): true {} /** @refcount 1 */ function imagecreate(int $width, int $height): GdImage|false {} @@ -635,7 +635,7 @@ function imagegd2(GdImage $image, ?string $file = null, int $chunk_size = 128, i function imagebmp(GdImage $image, $file = null, bool $compressed = true): bool {} #endif -function imagedestroy(GdImage $image): bool {} +function imagedestroy(GdImage $image): true {} function imagecolorallocate(GdImage $image, int $red, int $green, int $blue): int|false {} @@ -647,7 +647,7 @@ function imagecolorclosest(GdImage $image, int $red, int $green, int $blue): int function imagecolorclosesthwb(GdImage $image, int $red, int $green, int $blue): int {} -function imagecolordeallocate(GdImage $image, int $color): bool {} +function imagecolordeallocate(GdImage $image, int $color): true {} function imagecolorresolve(GdImage $image, int $red, int $green, int $blue): int {} @@ -661,25 +661,25 @@ function imagecolorset(GdImage $image, int $color, int $red, int $green, int $bl */ function imagecolorsforindex(GdImage $image, int $color): array {} -function imagegammacorrect(GdImage $image, float $input_gamma, float $output_gamma): bool {} +function imagegammacorrect(GdImage $image, float $input_gamma, float $output_gamma): true {} -function imagesetpixel(GdImage $image, int $x, int $y, int $color): bool {} +function imagesetpixel(GdImage $image, int $x, int $y, int $color): true {} -function imageline(GdImage $image, int $x1, int $y1, int $x2, int $y2, int $color): bool {} +function imageline(GdImage $image, int $x1, int $y1, int $x2, int $y2, int $color): true {} -function imagedashedline(GdImage $image, int $x1, int $y1, int $x2, int $y2, int $color): bool {} +function imagedashedline(GdImage $image, int $x1, int $y1, int $x2, int $y2, int $color): true {} -function imagerectangle(GdImage $image, int $x1, int $y1, int $x2, int $y2, int $color): bool {} +function imagerectangle(GdImage $image, int $x1, int $y1, int $x2, int $y2, int $color): true {} -function imagefilledrectangle(GdImage $image, int $x1, int $y1, int $x2, int $y2, int $color): bool {} +function imagefilledrectangle(GdImage $image, int $x1, int $y1, int $x2, int $y2, int $color): true {} -function imagearc(GdImage $image, int $center_x, int $center_y, int $width, int $height, int $start_angle, int $end_angle, int $color): bool {} +function imagearc(GdImage $image, int $center_x, int $center_y, int $width, int $height, int $start_angle, int $end_angle, int $color): true {} -function imageellipse(GdImage $image, int $center_x, int $center_y, int $width, int $height, int $color): bool {} +function imageellipse(GdImage $image, int $center_x, int $center_y, int $width, int $height, int $color): true {} -function imagefilltoborder(GdImage $image, int $x, int $y, int $border_color, int $color): bool {} +function imagefilltoborder(GdImage $image, int $x, int $y, int $border_color, int $color): true {} -function imagefill(GdImage $image, int $x, int $y, int $color): bool {} +function imagefill(GdImage $image, int $x, int $y, int $color): true {} function imagecolorstotal(GdImage $image): int {} @@ -697,27 +697,27 @@ function imagefontwidth(GdFont|int $font): int {} function imagefontheight(GdFont|int $font): int {} -function imagechar(GdImage $image, GdFont|int $font, int $x, int $y, string $char, int $color): bool {} +function imagechar(GdImage $image, GdFont|int $font, int $x, int $y, string $char, int $color): true {} -function imagecharup(GdImage $image, GdFont|int $font, int $x, int $y, string $char, int $color): bool {} +function imagecharup(GdImage $image, GdFont|int $font, int $x, int $y, string $char, int $color): true {} -function imagestring(GdImage $image, GdFont|int $font, int $x, int $y, string $string, int $color): bool {} +function imagestring(GdImage $image, GdFont|int $font, int $x, int $y, string $string, int $color): true {} -function imagestringup(GdImage $image, GdFont|int $font, int $x, int $y, string $string, int $color): bool {} +function imagestringup(GdImage $image, GdFont|int $font, int $x, int $y, string $string, int $color): true {} -function imagecopy(GdImage $dst_image, GdImage $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_width, int $src_height): bool {} +function imagecopy(GdImage $dst_image, GdImage $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_width, int $src_height): true {} -function imagecopymerge(GdImage $dst_image, GdImage $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_width, int $src_height, int $pct): bool {} +function imagecopymerge(GdImage $dst_image, GdImage $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_width, int $src_height, int $pct): true {} -function imagecopymergegray(GdImage $dst_image, GdImage $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_width, int $src_height, int $pct): bool {} +function imagecopymergegray(GdImage $dst_image, GdImage $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_width, int $src_height, int $pct): true {} -function imagecopyresized(GdImage $dst_image, GdImage $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $dst_width, int $dst_height, int $src_width, int $src_height): bool {} +function imagecopyresized(GdImage $dst_image, GdImage $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $dst_width, int $dst_height, int $src_width, int $src_height): true {} function imagesx(GdImage $image): int {} function imagesy(GdImage $image): int {} -function imagesetclip(GdImage $image, int $x1, int $y1, int $x2, int $y2): bool {} +function imagesetclip(GdImage $image, int $x1, int $y1, int $x2, int $y2): true {} /** * @return array @@ -756,9 +756,9 @@ function imagefilter(GdImage $image, int $filter, ...$args): bool {} function imageconvolution(GdImage $image, array $matrix, float $divisor, float $offset): bool {} -function imageflip(GdImage $image, int $mode): bool {} +function imageflip(GdImage $image, int $mode): true {} -function imageantialias(GdImage $image, bool $enable): bool {} +function imageantialias(GdImage $image, bool $enable): true {} /** @refcount 1 */ function imagecrop(GdImage $image, array $rectangle): GdImage|false {} @@ -793,4 +793,4 @@ function imagesetinterpolation(GdImage $image, int $method = IMG_BILINEAR_FIXED) * @return array|true * @refcount 1 */ -function imageresolution(GdImage $image, ?int $resolution_x = null, ?int $resolution_y = null): array|bool {} +function imageresolution(GdImage $image, ?int $resolution_x = null, ?int $resolution_y = null): array|true {} diff --git a/ext/gd/gd_arginfo.h b/ext/gd/gd_arginfo.h index 02f57e52ba940..5cf4f2f29a9bd 100644 --- a/ext/gd/gd_arginfo.h +++ b/ext/gd/gd_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0f8a22bff1d123313f37da400500e573baace837 */ + * Stub hash: 94822f6472750c646fc138f383278ca692b39d27 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_gd_info, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -30,17 +30,17 @@ ZEND_END_ARG_INFO() #define arginfo_imagepalettetotruecolor arginfo_imageistruecolor -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecolormatch, 0, 2, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecolormatch, 0, 2, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image1, GdImage, 0) ZEND_ARG_OBJ_INFO(0, image2, GdImage, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagesetthickness, 0, 2, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagesetthickness, 0, 2, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, thickness, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagefilledellipse, 0, 6, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagefilledellipse, 0, 6, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, center_x, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, center_y, IS_LONG, 0) @@ -49,7 +49,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagefilledellipse, 0, 6, _IS_BO ZEND_ARG_TYPE_INFO(0, color, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagefilledarc, 0, 9, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagefilledarc, 0, 9, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, center_x, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, center_y, IS_LONG, 0) @@ -61,14 +61,14 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagefilledarc, 0, 9, _IS_BOOL, ZEND_ARG_TYPE_INFO(0, style, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagealphablending, 0, 2, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagealphablending, 0, 2, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, enable, _IS_BOOL, 0) ZEND_END_ARG_INFO() #define arginfo_imagesavealpha arginfo_imagealphablending -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagelayereffect, 0, 2, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagelayereffect, 0, 2, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, effect, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -93,7 +93,7 @@ ZEND_END_ARG_INFO() #define arginfo_imagecolorexactalpha arginfo_imagecolorresolvealpha -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecopyresampled, 0, 10, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecopyresampled, 0, 10, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, dst_image, GdImage, 0) ZEND_ARG_OBJ_INFO(0, src_image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, dst_x, IS_LONG, 0) @@ -122,12 +122,12 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_imagerotate, 0, 3, GdImage, ZEND_ARG_TYPE_INFO(0, background_color, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagesettile, 0, 2, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagesettile, 0, 2, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_OBJ_INFO(0, tile, GdImage, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagesetbrush, 0, 2, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagesetbrush, 0, 2, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_OBJ_INFO(0, brush, GdImage, 0) ZEND_END_ARG_INFO() @@ -274,7 +274,9 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagebmp, 0, 1, _IS_BOOL, 0) ZEND_END_ARG_INFO() #endif -#define arginfo_imagedestroy arginfo_imageistruecolor +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagedestroy, 0, 1, IS_TRUE, 0) + ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) +ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imagecolorallocate, 0, 4, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) @@ -303,7 +305,7 @@ ZEND_END_ARG_INFO() #define arginfo_imagecolorclosesthwb arginfo_imagecolorclosest -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecolordeallocate, 0, 2, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecolordeallocate, 0, 2, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, color, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -326,20 +328,20 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecolorsforindex, 0, 2, IS_AR ZEND_ARG_TYPE_INFO(0, color, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagegammacorrect, 0, 3, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagegammacorrect, 0, 3, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, input_gamma, IS_DOUBLE, 0) ZEND_ARG_TYPE_INFO(0, output_gamma, IS_DOUBLE, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagesetpixel, 0, 4, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagesetpixel, 0, 4, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, x, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, y, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, color, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imageline, 0, 6, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imageline, 0, 6, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, x1, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, y1, IS_LONG, 0) @@ -354,7 +356,7 @@ ZEND_END_ARG_INFO() #define arginfo_imagefilledrectangle arginfo_imageline -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagearc, 0, 8, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagearc, 0, 8, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, center_x, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, center_y, IS_LONG, 0) @@ -367,7 +369,7 @@ ZEND_END_ARG_INFO() #define arginfo_imageellipse arginfo_imagefilledellipse -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagefilltoborder, 0, 5, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagefilltoborder, 0, 5, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, x, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, y, IS_LONG, 0) @@ -408,7 +410,7 @@ ZEND_END_ARG_INFO() #define arginfo_imagefontheight arginfo_imagefontwidth -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagechar, 0, 6, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagechar, 0, 6, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_OBJ_TYPE_MASK(0, font, GdFont, MAY_BE_LONG, NULL) ZEND_ARG_TYPE_INFO(0, x, IS_LONG, 0) @@ -419,7 +421,7 @@ ZEND_END_ARG_INFO() #define arginfo_imagecharup arginfo_imagechar -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagestring, 0, 6, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagestring, 0, 6, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_OBJ_TYPE_MASK(0, font, GdFont, MAY_BE_LONG, NULL) ZEND_ARG_TYPE_INFO(0, x, IS_LONG, 0) @@ -430,7 +432,7 @@ ZEND_END_ARG_INFO() #define arginfo_imagestringup arginfo_imagestring -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecopy, 0, 8, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecopy, 0, 8, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, dst_image, GdImage, 0) ZEND_ARG_OBJ_INFO(0, src_image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, dst_x, IS_LONG, 0) @@ -441,7 +443,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecopy, 0, 8, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, src_height, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecopymerge, 0, 9, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagecopymerge, 0, 9, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, dst_image, GdImage, 0) ZEND_ARG_OBJ_INFO(0, src_image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, dst_x, IS_LONG, 0) @@ -461,7 +463,7 @@ ZEND_END_ARG_INFO() #define arginfo_imagesy arginfo_imagecolorstotal -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagesetclip, 0, 5, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagesetclip, 0, 5, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, x1, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, y1, IS_LONG, 0) @@ -512,7 +514,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imageconvolution, 0, 4, _IS_BOOL ZEND_ARG_TYPE_INFO(0, offset, IS_DOUBLE, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imageflip, 0, 2, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imageflip, 0, 2, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO(0, mode, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -561,7 +563,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagesetinterpolation, 0, 1, _IS ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, method, IS_LONG, 0, "IMG_BILINEAR_FIXED") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imageresolution, 0, 1, MAY_BE_ARRAY|MAY_BE_BOOL) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imageresolution, 0, 1, MAY_BE_ARRAY|MAY_BE_TRUE) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, resolution_x, IS_LONG, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, resolution_y, IS_LONG, 1, "null") diff --git a/ext/gd/tests/gh17984.phpt b/ext/gd/tests/gh17984.phpt new file mode 100644 index 0000000000000..c46c455799e0f --- /dev/null +++ b/ext/gd/tests/gh17984.phpt @@ -0,0 +1,44 @@ +--TEST-- +GH-17984: array of references handling +--EXTENSIONS-- +gd +--FILE-- + +--EXPECT-- +object(GdImage)#2 (0) { +} +array(6) { + [0]=> + float(2028) + [1]=> + float(46) + [2]=> + float(138) + [3]=> + float(4) + [4]=> + float(233) + [5]=> + float(7) +} +bool(true) +bool(true) +bool(true) diff --git a/ext/gd/tests/gh18243.phpt b/ext/gd/tests/gh18243.phpt new file mode 100644 index 0000000000000..3235098a3dcc2 --- /dev/null +++ b/ext/gd/tests/gh18243.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-18243: imagefttext underflow/overflow on $size +--EXTENSIONS-- +gd +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +try { + imagettftext($im, PHP_INT_MIN, 0, 15, 60, 0, $font, ""); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + imagettftext($im, NAN, 0, 15, 60, 0, $font, ""); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + imagettftext($im, INF, 0, 15, 60, 0, $font, ""); +} catch (\ValueError $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +imagettftext(): Argument #2 ($size) must be between %i and %d +imagettftext(): Argument #2 ($size) must be between %i and %d +imagettftext(): Argument #2 ($size) must be finite +imagettftext(): Argument #2 ($size) must be between %i and %d diff --git a/ext/gd/tests/imagecrop_overflow.phpt b/ext/gd/tests/imagecrop_overflow.phpt new file mode 100644 index 0000000000000..3331a6267168a --- /dev/null +++ b/ext/gd/tests/imagecrop_overflow.phpt @@ -0,0 +1,45 @@ +--TEST-- +imagecrop() overflows when the combo x/width or y/height is over INT_MAX or under INT_MIN. +--EXTENSIONS-- +gd +--FILE-- + 2147483647, "y" => 2147483647, "width" => 10, "height" => 10]; + +try { + imagecrop($img, $arr); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +$arr = ["x" => -2147483648, "y" => 0, "width" => -10, "height" => 10]; + +try { + imagecrop($img, $arr); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +$arr = ["x" => 1, "y" => 2147483647, "width" => 10, "height" => 10]; + +try { + imagecrop($img, $arr); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +$arr = ["x" => 1, "y" => -2147483648, "width" => 10, "height" => -10]; + +try { + imagecrop($img, $arr); +} catch (\ValueError $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +imagecrop(): Argument #2 ($rectangle) overflow with "x" and "width" keys +imagecrop(): Argument #2 ($rectangle) underflow with "x" and "width" keys +imagecrop(): Argument #2 ($rectangle) overflow with "y" and "height" keys +imagecrop(): Argument #2 ($rectangle) underflow with "y" and "height" keys diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index f38ffef17aa32..8cf20c90fc7a2 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -480,7 +480,8 @@ static int gmp_compare(zval *op1, zval *op2) /* {{{ */ return ZEND_UNCOMPARABLE; } - return ZEND_THREEWAY_COMPARE(mpz_cmp(gmp_op1, gmp_op2), 0); + int ret = mpz_cmp(gmp_op1, gmp_op2); /* avoid multiple evaluations */ + return ZEND_THREEWAY_COMPARE(ret, 0); } /* }}} */ @@ -514,7 +515,7 @@ static int gmp_unserialize(zval *object, zend_class_entry *ce, const unsigned ch mpz_ptr gmpnum; const unsigned char *p, *max; zval *zv; - int retval = FAILURE; + zend_result retval = FAILURE; php_unserialize_data_t unserialize_data; zend_object *zobj; @@ -1422,7 +1423,8 @@ ZEND_FUNCTION(gmp_cmp) GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) ZEND_PARSE_PARAMETERS_END(); - RETURN_LONG(ZEND_THREEWAY_COMPARE(mpz_cmp(gmpnum_a, gmpnum_b), 0)); + int ret = mpz_cmp(gmpnum_a, gmpnum_b); /* avoid multiple evaluations */ + RETURN_LONG(ZEND_THREEWAY_COMPARE(ret, 0)); } /* }}} */ diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c index b61d253c5d4be..157ee41a11a05 100644 --- a/ext/iconv/iconv.c +++ b/ext/iconv/iconv.c @@ -63,15 +63,15 @@ #define PHP_ICONV_IMPL_VALUE "unknown" #endif -static char *get_iconv_version(void) { - char *version = "unknown"; +static const char *get_iconv_version(void) { + const char *version = "unknown"; #ifdef HAVE_LIBICONV static char buf[16]; snprintf(buf, sizeof(buf), "%d.%d", _libiconv_version >> 8, _libiconv_version & 0xff); version = buf; #elif defined(HAVE_GLIBC_ICONV) - version = (char *) gnu_get_libc_version(); + version = gnu_get_libc_version(); #endif return version; @@ -243,7 +243,7 @@ PHP_MSHUTDOWN_FUNCTION(miconv) /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(miconv) { - zval *iconv_impl, *iconv_ver; + const zval *iconv_impl, *iconv_ver; iconv_impl = zend_get_constant_str("ICONV_IMPL", sizeof("ICONV_IMPL")-1); iconv_ver = zend_get_constant_str("ICONV_VERSION", sizeof("ICONV_VERSION")-1); @@ -298,17 +298,18 @@ static php_output_handler *php_iconv_output_handler_init(const char *handler_nam static zend_result php_iconv_output_handler(void **nothing, php_output_context *output_context) { - char *s, *content_type, *mimetype = NULL; - int output_status, mimetype_len = 0; + char *content_type, *mimetype = NULL; if (output_context->op & PHP_OUTPUT_HANDLER_START) { - output_status = php_output_get_status(); + int output_status = php_output_get_status(); if (output_status & PHP_OUTPUT_SENT) { return FAILURE; } + int mimetype_len = 0; if (SG(sapi_headers).mimetype && !strncasecmp(SG(sapi_headers).mimetype, "text/", 5)) { - if ((s = strchr(SG(sapi_headers).mimetype,';')) == NULL){ + const char *s = strchr(SG(sapi_headers).mimetype,';'); + if (s == NULL){ mimetype = SG(sapi_headers).mimetype; } else { mimetype = SG(sapi_headers).mimetype; @@ -320,7 +321,7 @@ static zend_result php_iconv_output_handler(void **nothing, php_output_context * if (mimetype != NULL && (!(output_context->op & PHP_OUTPUT_HANDLER_CLEAN) || ((output_context->op & PHP_OUTPUT_HANDLER_START) && !(output_context->op & PHP_OUTPUT_HANDLER_FINAL)))) { size_t len; - char *p = strstr(get_output_encoding(), "//"); + const char *p = strstr(get_output_encoding(), "//"); if (p) { len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%.*s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, (int) (p - get_output_encoding()), get_output_encoding()); @@ -417,16 +418,16 @@ static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd /* {{{ */ #ifdef ICONV_BROKEN_IGNORE -static int _php_check_ignore(const char *charset) +static bool _php_check_ignore(const char *charset) { size_t clen = strlen(charset); if (clen >= 9 && strcmp("//IGNORE", charset+clen-8) == 0) { - return 1; + return true; } if (clen >= 19 && strcmp("//IGNORE//TRANSLIT", charset+clen-18) == 0) { - return 1; + return true; } - return 0; + return false; } #else #define _php_check_ignore(x) (0) @@ -442,7 +443,7 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len, size_t bsz, result = 0; php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS; zend_string *out_buf; - int ignore_ilseq = _php_check_ignore(out_charset); + bool ignore_ilseq = _php_check_ignore(out_charset); *out = NULL; @@ -559,7 +560,7 @@ static php_iconv_err_t _php_iconv_strlen(size_t *pretval, const char *str, size_ size_t out_left; size_t cnt; - int more; + bool more; *pretval = (size_t)-1; @@ -636,7 +637,7 @@ static php_iconv_err_t _php_iconv_substr(smart_str *pretval, size_t cnt; size_t total_len; - int more; + bool more; err = _php_iconv_strlen(&total_len, str, nbytes, enc); if (err != PHP_ICONV_ERR_SUCCESS) { @@ -774,8 +775,7 @@ static php_iconv_err_t _php_iconv_strpos(size_t *pretval, size_t ndl_buf_left; size_t match_ofs; - int more; - size_t iconv_ret; + bool more; *pretval = (size_t)-1; @@ -812,7 +812,7 @@ static php_iconv_err_t _php_iconv_strpos(size_t *pretval, more = in_left > 0; - iconv_ret = iconv(cd, more ? (ICONV_CONST char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); + size_t iconv_ret = iconv(cd, more ? (ICONV_CONST char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); if (out_left == sizeof(buf)) { break; } @@ -2255,11 +2255,7 @@ PHP_FUNCTION(iconv_set_encoding) retval = zend_alter_ini_entry(name, charset, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(name, 0); - if (retval == SUCCESS) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(retval == SUCCESS); } /* }}} */ @@ -2577,7 +2573,7 @@ static php_stream_filter *php_iconv_stream_filter_factory_create(const char *nam { php_stream_filter *retval = NULL; php_iconv_stream_filter *inst; - char *from_charset = NULL, *to_charset = NULL; + const char *from_charset = NULL, *to_charset = NULL; size_t from_charset_len, to_charset_len; if ((from_charset = strchr(name, '.')) == NULL) { diff --git a/ext/iconv/php_iconv.h b/ext/iconv/php_iconv.h index 7bc1cce0df9f5..fcabdfaf6449e 100644 --- a/ext/iconv/php_iconv.h +++ b/ext/iconv/php_iconv.h @@ -67,7 +67,7 @@ ZEND_TSRMLS_CACHE_EXTERN() /* {{{ typedef enum php_iconv_err_t */ typedef enum _php_iconv_err_t { - PHP_ICONV_ERR_SUCCESS = SUCCESS, + PHP_ICONV_ERR_SUCCESS = 0, PHP_ICONV_ERR_CONVERTER = 1, PHP_ICONV_ERR_WRONG_CHARSET = 2, PHP_ICONV_ERR_TOO_BIG = 3, diff --git a/ext/intl/collator/collator_sort.c b/ext/intl/collator/collator_sort.c index c28ffb82cf737..75466aacb07af 100644 --- a/ext/intl/collator/collator_sort.c +++ b/ext/intl/collator/collator_sort.c @@ -469,7 +469,8 @@ PHP_FUNCTION( collator_sort_with_sort_keys ) ZVAL_COPY_VALUE(&garbage, array); /* for resulting hash we'll assign new hash keys rather then reordering */ - array_init(array); + array_init_size(array, sortKeyCount); + zend_hash_real_init_packed(Z_ARRVAL_P(array)); for( j = 0; j < sortKeyCount; j++ ) { diff --git a/ext/intl/converter/converter.c b/ext/intl/converter/converter.c index e046661a83660..3aa7a53aa485b 100644 --- a/ext/intl/converter/converter.c +++ b/ext/intl/converter/converter.c @@ -294,7 +294,8 @@ static void php_converter_from_u_callback(const void *context, zval zargs[4]; ZVAL_LONG(&zargs[0], reason); - array_init(&zargs[1]); + array_init_size(&zargs[1], length); + zend_hash_real_init_packed(Z_ARRVAL(zargs[1])); int i = 0; while (i < length) { UChar32 c; @@ -738,13 +739,13 @@ PHP_METHOD(UConverter, transcode) { zval *tmpzval; if (U_SUCCESS(error) && - (tmpzval = zend_hash_str_find(Z_ARRVAL_P(options), "from_subst", sizeof("from_subst") - 1)) != NULL && + (tmpzval = zend_hash_str_find_deref(Z_ARRVAL_P(options), "from_subst", sizeof("from_subst") - 1)) != NULL && Z_TYPE_P(tmpzval) == IS_STRING) { error = U_ZERO_ERROR; ucnv_setSubstChars(src_cnv, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval) & 0x7F, &error); } if (U_SUCCESS(error) && - (tmpzval = zend_hash_str_find(Z_ARRVAL_P(options), "to_subst", sizeof("to_subst") - 1)) != NULL && + (tmpzval = zend_hash_str_find_deref(Z_ARRVAL_P(options), "to_subst", sizeof("to_subst") - 1)) != NULL && Z_TYPE_P(tmpzval) == IS_STRING) { error = U_ZERO_ERROR; ucnv_setSubstChars(dest_cnv, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval) & 0x7F, &error); @@ -807,7 +808,8 @@ PHP_METHOD(UConverter, getAvailable) { intl_error_reset(NULL); - array_init(return_value); + array_init_size(return_value, count); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for(i = 0; i < count; i++) { const char *name = ucnv_getAvailableName(i); add_next_index_string(return_value, name); @@ -833,7 +835,8 @@ PHP_METHOD(UConverter, getAliases) { RETURN_FALSE; } - array_init(return_value); + array_init_size(return_value, count); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for(i = 0; i < count; i++) { const char *alias; @@ -856,8 +859,9 @@ PHP_METHOD(UConverter, getStandards) { ZEND_PARSE_PARAMETERS_NONE(); intl_error_reset(NULL); - array_init(return_value); count = ucnv_countStandards(); + array_init_size(return_value, count); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for(i = 0; i < count; i++) { UErrorCode error = U_ZERO_ERROR; const char *name = ucnv_getStandard(i, &error); diff --git a/ext/intl/dateformat/dateformat_format.c b/ext/intl/dateformat/dateformat_format.c index 0d01323353026..f4ef8a40d6458 100644 --- a/ext/intl/dateformat/dateformat_format.c +++ b/ext/intl/dateformat/dateformat_format.c @@ -64,7 +64,7 @@ static int32_t internal_get_arr_ele(IntlDateFormatter_object *dfo, return result; } - if ((ele_value = zend_hash_str_find(hash_arr, key_name, strlen(key_name))) != NULL) { + if ((ele_value = zend_hash_str_find_deref(hash_arr, key_name, strlen(key_name))) != NULL) { if(Z_TYPE_P(ele_value) != IS_LONG) { spprintf(&message, 0, "datefmt_format: parameter array contains " "a non-integer element for key '%s'", key_name); diff --git a/ext/intl/formatter/formatter.stub.php b/ext/intl/formatter/formatter.stub.php index e335698688d64..ca94a2652bbe4 100644 --- a/ext/intl/formatter/formatter.stub.php +++ b/ext/intl/formatter/formatter.stub.php @@ -11,6 +11,10 @@ class NumberFormatter public const int PATTERN_DECIMAL = UNKNOWN; /** @cvalue UNUM_DECIMAL */ public const int DECIMAL = UNKNOWN; + /** @cvalue UNUM_DECIMAL_COMPACT_SHORT */ + public const int DECIMAL_COMPACT_SHORT = UNKNOWN; + /** @cvalue UNUM_DECIMAL_COMPACT_LONG */ + public const int DECIMAL_COMPACT_LONG = UNKNOWN; /** @cvalue UNUM_CURRENCY */ public const int CURRENCY = UNKNOWN; /** @cvalue UNUM_PERCENT */ @@ -27,8 +31,16 @@ class NumberFormatter public const int PATTERN_RULEBASED = UNKNOWN; /** @cvalue UNUM_IGNORE */ public const int IGNORE = UNKNOWN; + /** @cvalue UNUM_CURRENCY_ISO */ + public const int CURRENCY_ISO = UNKNOWN; + /** @cvalue UNUM_CURRENCY_PLURAL */ + public const int CURRENCY_PLURAL = UNKNOWN; /** @cvalue UNUM_CURRENCY_ACCOUNTING */ public const int CURRENCY_ACCOUNTING = UNKNOWN; + /** @cvalue UNUM_CASH_CURRENCY */ + public const int CASH_CURRENCY = UNKNOWN; + /** @cvalue UNUM_CURRENCY_STANDARD */ + public const int CURRENCY_STANDARD = UNKNOWN; /** @cvalue UNUM_DEFAULT */ public const int DEFAULT_STYLE = UNKNOWN; diff --git a/ext/intl/formatter/formatter_arginfo.h b/ext/intl/formatter/formatter_arginfo.h index 0e3d8b797e721..b872b0dc20f46 100644 --- a/ext/intl/formatter/formatter_arginfo.h +++ b/ext/intl/formatter/formatter_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: caaa6ff408bfd88ec9bb998ffd753f4de971ccff */ + * Stub hash: d886941aa76837aed1da08845dbaff9442107203 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_NumberFormatter___construct, 0, 0, 2) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 0) @@ -137,6 +137,18 @@ static zend_class_entry *register_class_NumberFormatter(void) zend_declare_typed_class_constant(class_entry, const_DECIMAL_name, &const_DECIMAL_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_DECIMAL_name); + zval const_DECIMAL_COMPACT_SHORT_value; + ZVAL_LONG(&const_DECIMAL_COMPACT_SHORT_value, UNUM_DECIMAL_COMPACT_SHORT); + zend_string *const_DECIMAL_COMPACT_SHORT_name = zend_string_init_interned("DECIMAL_COMPACT_SHORT", sizeof("DECIMAL_COMPACT_SHORT") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_DECIMAL_COMPACT_SHORT_name, &const_DECIMAL_COMPACT_SHORT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_DECIMAL_COMPACT_SHORT_name); + + zval const_DECIMAL_COMPACT_LONG_value; + ZVAL_LONG(&const_DECIMAL_COMPACT_LONG_value, UNUM_DECIMAL_COMPACT_LONG); + zend_string *const_DECIMAL_COMPACT_LONG_name = zend_string_init_interned("DECIMAL_COMPACT_LONG", sizeof("DECIMAL_COMPACT_LONG") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_DECIMAL_COMPACT_LONG_name, &const_DECIMAL_COMPACT_LONG_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_DECIMAL_COMPACT_LONG_name); + zval const_CURRENCY_value; ZVAL_LONG(&const_CURRENCY_value, UNUM_CURRENCY); zend_string *const_CURRENCY_name = zend_string_init_interned("CURRENCY", sizeof("CURRENCY") - 1, 1); @@ -185,12 +197,36 @@ static zend_class_entry *register_class_NumberFormatter(void) zend_declare_typed_class_constant(class_entry, const_IGNORE_name, &const_IGNORE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_IGNORE_name); + zval const_CURRENCY_ISO_value; + ZVAL_LONG(&const_CURRENCY_ISO_value, UNUM_CURRENCY_ISO); + zend_string *const_CURRENCY_ISO_name = zend_string_init_interned("CURRENCY_ISO", sizeof("CURRENCY_ISO") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_CURRENCY_ISO_name, &const_CURRENCY_ISO_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_CURRENCY_ISO_name); + + zval const_CURRENCY_PLURAL_value; + ZVAL_LONG(&const_CURRENCY_PLURAL_value, UNUM_CURRENCY_PLURAL); + zend_string *const_CURRENCY_PLURAL_name = zend_string_init_interned("CURRENCY_PLURAL", sizeof("CURRENCY_PLURAL") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_CURRENCY_PLURAL_name, &const_CURRENCY_PLURAL_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_CURRENCY_PLURAL_name); + zval const_CURRENCY_ACCOUNTING_value; ZVAL_LONG(&const_CURRENCY_ACCOUNTING_value, UNUM_CURRENCY_ACCOUNTING); zend_string *const_CURRENCY_ACCOUNTING_name = zend_string_init_interned("CURRENCY_ACCOUNTING", sizeof("CURRENCY_ACCOUNTING") - 1, 1); zend_declare_typed_class_constant(class_entry, const_CURRENCY_ACCOUNTING_name, &const_CURRENCY_ACCOUNTING_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_CURRENCY_ACCOUNTING_name); + zval const_CASH_CURRENCY_value; + ZVAL_LONG(&const_CASH_CURRENCY_value, UNUM_CASH_CURRENCY); + zend_string *const_CASH_CURRENCY_name = zend_string_init_interned("CASH_CURRENCY", sizeof("CASH_CURRENCY") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_CASH_CURRENCY_name, &const_CASH_CURRENCY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_CASH_CURRENCY_name); + + zval const_CURRENCY_STANDARD_value; + ZVAL_LONG(&const_CURRENCY_STANDARD_value, UNUM_CURRENCY_STANDARD); + zend_string *const_CURRENCY_STANDARD_name = zend_string_init_interned("CURRENCY_STANDARD", sizeof("CURRENCY_STANDARD") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_CURRENCY_STANDARD_name, &const_CURRENCY_STANDARD_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_CURRENCY_STANDARD_name); + zval const_DEFAULT_STYLE_value; ZVAL_LONG(&const_DEFAULT_STYLE_value, UNUM_DEFAULT); zend_string *const_DEFAULT_STYLE_name = zend_string_init_interned("DEFAULT_STYLE", sizeof("DEFAULT_STYLE") - 1, 1); diff --git a/ext/intl/idn/idn.c b/ext/intl/idn/idn.c index 62ee83f62f9ba..cd4546ad7f8bb 100644 --- a/ext/intl/idn/idn.c +++ b/ext/intl/idn/idn.c @@ -57,6 +57,7 @@ static void php_intl_idn_to_46(INTERNAL_FUNCTION_PARAMETERS, UErrorCode status = U_ZERO_ERROR; UIDNA *uts46; int32_t len; + int32_t buffer_capac; zend_string *buffer; UIDNAInfo info = UIDNA_INFO_INITIALIZER; @@ -66,36 +67,25 @@ static void php_intl_idn_to_46(INTERNAL_FUNCTION_PARAMETERS, } if (mode == INTL_IDN_TO_ASCII) { - const int32_t buffer_capac = 255; + buffer_capac = 255; buffer = zend_string_alloc(buffer_capac, 0); len = uidna_nameToASCII_UTF8(uts46, ZSTR_VAL(domain), ZSTR_LEN(domain), ZSTR_VAL(buffer), buffer_capac, &info, &status); - if (len >= buffer_capac || php_intl_idn_check_status(status, "failed to convert name") == FAILURE) { - uidna_close(uts46); - zend_string_efree(buffer); - RETURN_FALSE; - } } else { - const int32_t buffer_capac = 252*4; + buffer_capac = 252*4; buffer = zend_string_alloc(buffer_capac, 0); len = uidna_nameToUnicodeUTF8(uts46, ZSTR_VAL(domain), ZSTR_LEN(domain), ZSTR_VAL(buffer), buffer_capac, &info, &status); - if (len >= buffer_capac || php_intl_idn_check_status(status, "failed to convert name") == FAILURE) { - uidna_close(uts46); - zend_string_efree(buffer); - RETURN_FALSE; - } + } + if (len >= buffer_capac || php_intl_idn_check_status(status, "failed to convert name") == FAILURE) { + uidna_close(uts46); + zend_string_efree(buffer); + RETURN_FALSE; } ZSTR_VAL(buffer)[len] = '\0'; ZSTR_LEN(buffer) = len; - if (info.errors == 0) { - RETVAL_STR_COPY(buffer); - } else { - RETVAL_FALSE; - } - if (idna_info) { add_assoc_str_ex(idna_info, "result", sizeof("result")-1, zend_string_copy(buffer)); add_assoc_bool_ex(idna_info, "isTransitionalDifferent", @@ -103,7 +93,13 @@ static void php_intl_idn_to_46(INTERNAL_FUNCTION_PARAMETERS, add_assoc_long_ex(idna_info, "errors", sizeof("errors")-1, (zend_long)info.errors); } - zend_string_release(buffer); + if (info.errors == 0) { + RETVAL_STR(buffer); + } else { + zend_string_release_ex(buffer, false); + RETVAL_FALSE; + } + uidna_close(uts46); } diff --git a/ext/intl/locale/locale.stub.php b/ext/intl/locale/locale.stub.php index 1ec2af308edd2..fcda8f68409ce 100644 --- a/ext/intl/locale/locale.stub.php +++ b/ext/intl/locale/locale.stub.php @@ -133,4 +133,9 @@ public static function canonicalize(string $locale): ?string {} * @alias locale_accept_from_http */ public static function acceptFromHttp(string $header): string|false {} + + /** + * @alias locale_is_right_to_left + */ + public static function isRightToLeft(string $locale): bool {} } diff --git a/ext/intl/locale/locale_arginfo.h b/ext/intl/locale/locale_arginfo.h index 7bba882d20457..40426a1aa9e78 100644 --- a/ext/intl/locale/locale_arginfo.h +++ b/ext/intl/locale/locale_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 59861342e0075231d2a576afb2d5df6973d70684 */ + * Stub hash: f09cfd61f3e20576c7f6d5da17a6d9c009d6ab64 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Locale_getDefault, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -62,6 +62,10 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_Locale_acceptFro ZEND_ARG_TYPE_INFO(0, header, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Locale_isRightToLeft, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_FUNCTION(locale_get_default); ZEND_FUNCTION(locale_set_default); ZEND_FUNCTION(locale_get_primary_language); @@ -80,6 +84,7 @@ ZEND_FUNCTION(locale_filter_matches); ZEND_FUNCTION(locale_lookup); ZEND_FUNCTION(locale_canonicalize); ZEND_FUNCTION(locale_accept_from_http); +ZEND_FUNCTION(locale_is_right_to_left); static const zend_function_entry class_Locale_methods[] = { ZEND_RAW_FENTRY("getDefault", zif_locale_get_default, arginfo_class_Locale_getDefault, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL, NULL) @@ -100,6 +105,7 @@ static const zend_function_entry class_Locale_methods[] = { ZEND_RAW_FENTRY("lookup", zif_locale_lookup, arginfo_class_Locale_lookup, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL, NULL) ZEND_RAW_FENTRY("canonicalize", zif_locale_canonicalize, arginfo_class_Locale_canonicalize, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL, NULL) ZEND_RAW_FENTRY("acceptFromHttp", zif_locale_accept_from_http, arginfo_class_Locale_acceptFromHttp, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL, NULL) + ZEND_RAW_FENTRY("isRightToLeft", zif_locale_is_right_to_left, arginfo_class_Locale_isRightToLeft, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL, NULL) ZEND_FE_END }; diff --git a/ext/intl/locale/locale_methods.c b/ext/intl/locale/locale_methods.c index 373d71d263604..bba52a90994cc 100644 --- a/ext/intl/locale/locale_methods.c +++ b/ext/intl/locale/locale_methods.c @@ -807,7 +807,7 @@ static int append_key_value(smart_str* loc_name, HashTable* hash_arr, char* key_ { zval *ele_value; - if ((ele_value = zend_hash_str_find(hash_arr , key_name, strlen(key_name))) != NULL ) { + if ((ele_value = zend_hash_str_find_deref(hash_arr , key_name, strlen(key_name))) != NULL ) { if(Z_TYPE_P(ele_value)!= IS_STRING ){ /* element value is not a string */ return FAILURE; @@ -850,7 +850,7 @@ static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr, int isFirstSubtag = 0; /* Variant/ Extlang/Private etc. */ - if ((ele_value = zend_hash_str_find( hash_arr , key_name , strlen(key_name))) != NULL) { + if ((ele_value = zend_hash_str_find_deref( hash_arr , key_name , strlen(key_name))) != NULL) { if( Z_TYPE_P(ele_value) == IS_STRING ){ add_prefix( loc_name , key_name); @@ -862,6 +862,7 @@ static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr, zval *data; ZEND_HASH_FOREACH_VAL(arr, data) { + ZVAL_DEREF(data); if(Z_TYPE_P(data) != IS_STRING) { return FAILURE; } @@ -893,7 +894,7 @@ static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr, isFirstSubtag = 0; for( i=0 ; i< max_value; i++ ){ snprintf( cur_key_name , 30, "%s%d", key_name , i); - if ((ele_value = zend_hash_str_find( hash_arr , cur_key_name , strlen(cur_key_name))) != NULL) { + if ((ele_value = zend_hash_str_find_deref( hash_arr , cur_key_name , strlen(cur_key_name))) != NULL) { if( Z_TYPE_P(ele_value)!= IS_STRING ){ /* variant is not a string */ return FAILURE; @@ -1426,6 +1427,7 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr, char **cur_arr = ecalloc(zend_hash_num_elements(hash_arr)*2, sizeof(char *)); ZEND_HASH_FOREACH_VAL(hash_arr, ele_value) { + ZVAL_DEREF(ele_value); /* convert the array to lowercase , also replace hyphens with the underscore and store it in cur_arr */ if(Z_TYPE_P(ele_value)!= IS_STRING) { /* element value is not a string */ @@ -1617,3 +1619,19 @@ PHP_FUNCTION(locale_accept_from_http) RETURN_STRINGL(resultLocale, len); } /* }}} */ + +PHP_FUNCTION(locale_is_right_to_left) +{ + char *locale; + size_t locale_len; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STRING(locale, locale_len) + ZEND_PARSE_PARAMETERS_END(); + + if (!locale_len) { + locale = (char *)intl_locale_get_default(); + } + + RETURN_BOOL(uloc_isRightToLeft(locale)); +} diff --git a/ext/intl/msgformat/msgformat_parse.c b/ext/intl/msgformat/msgformat_parse.c index c55671cf856a6..80ede995c42e7 100644 --- a/ext/intl/msgformat/msgformat_parse.c +++ b/ext/intl/msgformat/msgformat_parse.c @@ -42,7 +42,8 @@ static void msgfmt_do_parse(MessageFormatter_object *mfo, char *source, size_t s } INTL_METHOD_CHECK_STATUS(mfo, "Parsing failed"); - array_init(return_value); + array_init_size(return_value, count); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for(i=0;ichild, &ilen, &INTL_DATA_ERROR_CODE(source) ); INTL_METHOD_CHECK_STATUS(source, "Failed to retrieve vector value"); - array_init( return_value ); + array_init_size( return_value, ilen ); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for (i=0; i +--FILE-- + &$a , + 'tm_min' => 3, + 'tm_hour' => 19, + 'tm_mday' => 3, + 'tm_mon' => 3, + 'tm_year' => 105, +); +$fmt = datefmt_create('en_US', IntlDateFormatter::FULL, IntlDateFormatter::FULL, 'America/New_York', IntlDateFormatter::GREGORIAN); +$formatted = datefmt_format($fmt , $localtime_arr); +var_dump($formatted); +?> +--EXPECTF-- +string(%d) "Sunday, April 3, 2005 at 7:03:24%aPM Eastern Daylight Time" diff --git a/ext/intl/tests/formatter/currencies.phpt b/ext/intl/tests/formatter/currencies.phpt new file mode 100644 index 0000000000000..01c64a0480d37 --- /dev/null +++ b/ext/intl/tests/formatter/currencies.phpt @@ -0,0 +1,191 @@ +--TEST-- +NumberFormatter: currency formatting +----DESCRIPTION-- +Tests NumberFormatter with various currenct-related formatters. +--EXTENSIONS-- +intl +--FILE-- + NumberFormatter::CURRENCY, + 'CURRENCY_ACCOUNTING' => NumberFormatter::CURRENCY_ACCOUNTING, + 'CURRENCY_ISO' => NumberFormatter::CURRENCY_ISO, + 'CURRENCY_PLURAL' => NumberFormatter::CURRENCY_PLURAL, + 'CASH_CURRENCY' => NumberFormatter::CASH_CURRENCY, + 'CURRENCY_STANDARD' => NumberFormatter::CURRENCY_STANDARD, + ]; + + $numbers = [0, 1, 2, 123456789.42, -123456789.42, 456.789012]; + + $res_str = ''; + + foreach($locales as $locale) { + foreach ($formats as $formatLabel => $format) { + $res_str .= "$locale: $formatLabel\n"; + foreach ($numbers as $number) { + $fmt = ut_nfmt_create($locale, $format); + $res_str .= "$number => " . ut_nfmt_format_currency($fmt, $number, ut_nfmt_get_symbol($fmt, NumberFormatter::INTL_CURRENCY_SYMBOL)) . "\n"; + } + $res_str .= "\n"; + } + } + + return $res_str; +} + +include_once(__DIR__ . '/../ut_common.inc'); + +ut_run(); +?> +--EXPECT-- +ka-GE: CURRENCY +0 => 0,00 ₾ +1 => 1,00 ₾ +2 => 2,00 ₾ +123456789.42 => 123 456 789,42 ₾ +-123456789.42 => -123 456 789,42 ₾ +456.789012 => 456,79 ₾ + +ka-GE: CURRENCY_ACCOUNTING +0 => 0,00 ₾ +1 => 1,00 ₾ +2 => 2,00 ₾ +123456789.42 => 123 456 789,42 ₾ +-123456789.42 => -123 456 789,42 ₾ +456.789012 => 456,79 ₾ + +ka-GE: CURRENCY_ISO +0 => 0,00 GEL +1 => 1,00 GEL +2 => 2,00 GEL +123456789.42 => 123 456 789,42 GEL +-123456789.42 => -123 456 789,42 GEL +456.789012 => 456,79 GEL + +ka-GE: CURRENCY_PLURAL +0 => 0,00 ქართული ლარი +1 => 1,00 ქართული ლარი +2 => 2,00 ქართული ლარი +123456789.42 => 123 456 789,42 ქართული ლარი +-123456789.42 => -123 456 789,42 ქართული ლარი +456.789012 => 456,79 ქართული ლარი + +ka-GE: CASH_CURRENCY +0 => 0,00 ₾ +1 => 1,00 ₾ +2 => 2,00 ₾ +123456789.42 => 123 456 789,42 ₾ +-123456789.42 => -123 456 789,42 ₾ +456.789012 => 456,79 ₾ + +ka-GE: CURRENCY_STANDARD +0 => 0,00 ₾ +1 => 1,00 ₾ +2 => 2,00 ₾ +123456789.42 => 123 456 789,42 ₾ +-123456789.42 => -123 456 789,42 ₾ +456.789012 => 456,79 ₾ + +hi-IN: CURRENCY +0 => ₹0.00 +1 => ₹1.00 +2 => ₹2.00 +123456789.42 => ₹12,34,56,789.42 +-123456789.42 => -₹12,34,56,789.42 +456.789012 => ₹456.79 + +hi-IN: CURRENCY_ACCOUNTING +0 => ₹0.00 +1 => ₹1.00 +2 => ₹2.00 +123456789.42 => ₹12,34,56,789.42 +-123456789.42 => -₹12,34,56,789.42 +456.789012 => ₹456.79 + +hi-IN: CURRENCY_ISO +0 => INR 0.00 +1 => INR 1.00 +2 => INR 2.00 +123456789.42 => INR 12,34,56,789.42 +-123456789.42 => -INR 12,34,56,789.42 +456.789012 => INR 456.79 + +hi-IN: CURRENCY_PLURAL +0 => 0.00 भारतीय रुपया +1 => 1.00 भारतीय रुपया +2 => 2.00 भारतीय रुपए +123456789.42 => 12,34,56,789.42 भारतीय रुपए +-123456789.42 => -12,34,56,789.42 भारतीय रुपए +456.789012 => 456.79 भारतीय रुपए + +hi-IN: CASH_CURRENCY +0 => ₹0.00 +1 => ₹1.00 +2 => ₹2.00 +123456789.42 => ₹12,34,56,789.42 +-123456789.42 => -₹12,34,56,789.42 +456.789012 => ₹456.79 + +hi-IN: CURRENCY_STANDARD +0 => ₹0.00 +1 => ₹1.00 +2 => ₹2.00 +123456789.42 => ₹12,34,56,789.42 +-123456789.42 => -₹12,34,56,789.42 +456.789012 => ₹456.79 + +zh-TW: CURRENCY +0 => $0.00 +1 => $1.00 +2 => $2.00 +123456789.42 => $123,456,789.42 +-123456789.42 => -$123,456,789.42 +456.789012 => $456.79 + +zh-TW: CURRENCY_ACCOUNTING +0 => $0.00 +1 => $1.00 +2 => $2.00 +123456789.42 => $123,456,789.42 +-123456789.42 => ($123,456,789.42) +456.789012 => $456.79 + +zh-TW: CURRENCY_ISO +0 => TWD 0.00 +1 => TWD 1.00 +2 => TWD 2.00 +123456789.42 => TWD 123,456,789.42 +-123456789.42 => -TWD 123,456,789.42 +456.789012 => TWD 456.79 + +zh-TW: CURRENCY_PLURAL +0 => 0.00 新台幣 +1 => 1.00 新台幣 +2 => 2.00 新台幣 +123456789.42 => 123,456,789.42 新台幣 +-123456789.42 => -123,456,789.42 新台幣 +456.789012 => 456.79 新台幣 + +zh-TW: CASH_CURRENCY +0 => $0 +1 => $1 +2 => $2 +123456789.42 => $123,456,789 +-123456789.42 => -$123,456,789 +456.789012 => $457 + +zh-TW: CURRENCY_STANDARD +0 => $0.00 +1 => $1.00 +2 => $2.00 +123456789.42 => $123,456,789.42 +-123456789.42 => -$123,456,789.42 +456.789012 => $456.79 diff --git a/ext/intl/tests/formatter_format_decimal_compact.phpt b/ext/intl/tests/formatter_format_decimal_compact.phpt new file mode 100644 index 0000000000000..2c78f8787e0f4 --- /dev/null +++ b/ext/intl/tests/formatter_format_decimal_compact.phpt @@ -0,0 +1,57 @@ +--TEST-- +numfmt_format_currency() icu >= 4.8 +--EXTENSIONS-- +intl +--FILE-- + +--EXPECTF-- +en_UK: short = 1.2M +en_UK: long = 1.2 million +en_US: short = 1.2M +en_US: long = 1.2 million +ru: short = 1,2 млн +ru: long = 1,2 миллиона +zh_CN: short = 123万 +zh_CN: long = 123万 +ro: short = 1,2 mil. +ro: long = 1,2 milioane +uk: short = 1,2 млн +uk: long = 1,2 мільйона +en: short = 1.2M +en: long = 1.2 million +bg: short = 1,2 млн. +bg: long = 1,2 милиона \ No newline at end of file diff --git a/ext/intl/tests/intltz_get_offset_references.phpt b/ext/intl/tests/intltz_get_offset_references.phpt new file mode 100644 index 0000000000000..6f104863d2212 --- /dev/null +++ b/ext/intl/tests/intltz_get_offset_references.phpt @@ -0,0 +1,26 @@ +--TEST-- +intltz_get_offset references +--EXTENSIONS-- +intl +--FILE-- +a = $test->b = "hello"; + +$rawOffset =& $test->a; +$dstOffset =& $test->b; +intltz_get_offset($tz, 0.0, true, $rawOffset, $dstOffset); +var_dump($test); +?> +--EXPECT-- +object(Test)#2 (2) { + ["a"]=> + &string(7) "3600000" + ["b"]=> + &string(1) "0" +} diff --git a/ext/intl/tests/locale_compose_lookup_references.phpt b/ext/intl/tests/locale_compose_lookup_references.phpt new file mode 100644 index 0000000000000..f6a202f7512fa --- /dev/null +++ b/ext/intl/tests/locale_compose_lookup_references.phpt @@ -0,0 +1,29 @@ +--TEST-- +locale_compose()/locale_lookup() with values as references. +--EXTENSIONS-- +intl +--FILE-- + 'en', Locale::REGION_TAG => &$en]; + +var_dump(locale_compose($data)); + +$data = [ + 'language' => 'de', + 'script' => 'Hans', + 'region' => 'DE', + 'variant2' => 'fr', + 'variant1' => &$en, + 'private1' => 'private1', + 'private2' => 'private2', + ]; +var_dump(locale_compose($data)); +$data = ['de', &$en]; +var_dump(locale_lookup($data, "en", false, "en")); +?> +--EXPECT-- +string(5) "en_en" +string(36) "de_Hans_DE_en_fr_x_private1_private2" +string(2) "en" diff --git a/ext/intl/tests/locale_get_display_name8.phpt b/ext/intl/tests/locale_get_display_name8.phpt index e8c1ed958ac1c..aa91ee4c3b8ca 100644 --- a/ext/intl/tests/locale_get_display_name8.phpt +++ b/ext/intl/tests/locale_get_display_name8.phpt @@ -112,9 +112,9 @@ disp_locale=fr : display_name=slovène #Italie, NEDIS_KIRTI# disp_locale=de : display_name=Slowenisch #Italien, NEDIS_KIRTI# ----------------- locale='sl_IT_nedis-a-kirti-x-xyz' -disp_locale=en : display_name=Slovenian #Italy, NEDIS_A_KIRTI_X_XYZ# -disp_locale=fr : display_name=slovène #Italie, NEDIS_A_KIRTI_X_XYZ# -disp_locale=de : display_name=Slowenisch #Italien, NEDIS_A_KIRTI_X_XYZ# +disp_locale=en : display_name=Slovenian #Italy, NEDIS_A_KIRTI(_X_XYZ)?# +disp_locale=fr : display_name=slovène #Italie, NEDIS_A_KIRTI(_X_XYZ)?# +disp_locale=de : display_name=Slowenisch #Italien, NEDIS_A_KIRTI(_X_XYZ)?# ----------------- locale='sl_IT_rozaj' disp_locale=en : display_name=Slovenian #Italy, Resian# @@ -317,9 +317,9 @@ disp_locale=fr : display_name=anglais #États-Unis, attribute=islamcal# disp_locale=de : display_name=Englisch #Vereinigte Staaten, attribute=islamcal# ----------------- locale='zh-CN-a-myExt-x-private' -disp_locale=en : display_name=Chinese #China(, A_MYEXT_X_PRIVATE)?, a=myext, Private-Use=private# -disp_locale=fr : display_name=chinois #Chine(, A_MYEXT_X_PRIVATE)?, a=myext, usage privé=private# -disp_locale=de : display_name=Chinesisch #China(, A_MYEXT_X_PRIVATE)?, a=myext, Privatnutzung=private# +disp_locale=en : display_name=Chinese #China(, A_MYEXT(_X_PRIVATE)?)?, a=myext, Private-Use=private# +disp_locale=fr : display_name=chinois #Chine(, A_MYEXT(_X_PRIVATE)?)?, a=myext, usage privé=private# +disp_locale=de : display_name=Chinesisch #China(, A_MYEXT(_X_PRIVATE)?)?, a=myext, Privatnutzung=private# ----------------- locale='en-a-myExt-b-another' disp_locale=en : display_name=English #(A_MYEXT_B_ANOTHER, )?a=myext, b=another# diff --git a/ext/intl/tests/locale_get_display_variant2.phpt b/ext/intl/tests/locale_get_display_variant2.phpt index e56154902dde9..8e815e8c4e52a 100644 --- a/ext/intl/tests/locale_get_display_variant2.phpt +++ b/ext/intl/tests/locale_get_display_variant2.phpt @@ -248,9 +248,9 @@ disp_locale=fr : display_variant= disp_locale=de : display_variant= ----------------- locale='zh-CN-a-myExt-x-private' -disp_locale=en : display_variant=(A_MYEXT_X_PRIVATE)? -disp_locale=fr : display_variant=(A_MYEXT_X_PRIVATE)? -disp_locale=de : display_variant=(A_MYEXT_X_PRIVATE)? +disp_locale=en : display_variant=(A_MYEXT(_X_PRIVATE)?)? +disp_locale=fr : display_variant=(A_MYEXT(_X_PRIVATE)?)? +disp_locale=de : display_variant=(A_MYEXT(_X_PRIVATE)?)? ----------------- locale='en-a-myExt-b-another' disp_locale=en : display_variant=((A_)?MYEXT_B_ANOTHER)? diff --git a/ext/intl/tests/locale_is_right_to_left.phpt b/ext/intl/tests/locale_is_right_to_left.phpt new file mode 100644 index 0000000000000..c586582d42225 --- /dev/null +++ b/ext/intl/tests/locale_is_right_to_left.phpt @@ -0,0 +1,16 @@ +--TEST-- +locale_is_right_to_left +--EXTENSIONS-- +intl +--FILE-- + +--EXPECT-- +bool(false) +bool(false) +bool(false) +bool(true) diff --git a/ext/intl/tests/uconverter_transcode_references.phpt b/ext/intl/tests/uconverter_transcode_references.phpt new file mode 100644 index 0000000000000..a2b1be20d1dfe --- /dev/null +++ b/ext/intl/tests/uconverter_transcode_references.phpt @@ -0,0 +1,22 @@ +--TEST-- +UConverter::transcode issue with substitutes values as references +--EXTENSIONS-- +intl +--FILE-- + '?', 'to_subst' => &$subst); +var_dump(UConverter::transcode("This is an ascii string", 'ascii', 'utf-8', $opts)); +$opts = array('from_subst' => &$subst, 'to_subst' => '?'); +var_dump(UConverter::transcode("This is an ascii string", 'ascii', 'utf-8', $opts)); +// should yield the same results +$opts = array('from_subst' => '?', 'to_subst' => '??'); +var_dump(UConverter::transcode("This is an ascii string", 'ascii', 'utf-8', $opts)); +$opts = array('from_subst' => '??', 'to_subst' => '?'); +var_dump(UConverter::transcode("This is an ascii string", 'ascii', 'utf-8', $opts)); +?> +--EXPECT-- +bool(false) +string(23) "This is an ascii string" +bool(false) +string(23) "This is an ascii string" diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp index 21f847819a9c7..5d0a7dc445a75 100644 --- a/ext/intl/timezone/timezone_methods.cpp +++ b/ext/intl/timezone/timezone_methods.cpp @@ -440,7 +440,7 @@ U_CFUNC PHP_FUNCTION(intltz_get_offset) TIMEZONE_METHOD_INIT_VARS; if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), - "Odbz/z/", &object, TimeZone_ce_ptr, &date, &local, &rawOffsetArg, + "Odbzz", &object, TimeZone_ce_ptr, &date, &local, &rawOffsetArg, &dstOffsetArg) == FAILURE) { RETURN_THROWS(); } @@ -452,10 +452,8 @@ U_CFUNC PHP_FUNCTION(intltz_get_offset) INTL_METHOD_CHECK_STATUS(to, "error obtaining offset"); - zval_ptr_dtor(rawOffsetArg); - ZVAL_LONG(rawOffsetArg, rawOffset); - zval_ptr_dtor(dstOffsetArg); - ZVAL_LONG(dstOffsetArg, dstOffset); + ZEND_TRY_ASSIGN_REF_LONG(rawOffsetArg, rawOffset); + ZEND_TRY_ASSIGN_REF_LONG(dstOffsetArg, dstOffset); RETURN_TRUE; } diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index 53dd4cae2574a..c147b8eb23d73 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -283,13 +283,12 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, if ((prop_info->flags & ZEND_ACC_VIRTUAL) && !prop_info->hooks[ZEND_PROPERTY_HOOK_GET]) { continue; } - zend_read_property_ex(prop_info->ce, Z_OBJ_P(val), prop_info->name, /* silent */ true, &tmp); + data = zend_read_property_ex(prop_info->ce, Z_OBJ_P(val), prop_info->name, /* silent */ true, &tmp); if (EG(exception)) { PHP_JSON_HASH_UNPROTECT_RECURSION(recursion_rc); zend_release_properties(prop_ht); return FAILURE; } - data = &tmp; } if (need_comma) { diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index 90f3ba6a54f98..446db903958d2 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -859,6 +859,21 @@ static PHP_GINIT_FUNCTION(ldap) } /* }}} */ +/* {{{ PHP_RINIT_FUNCTION */ +static PHP_RINIT_FUNCTION(ldap) +{ +#if defined(COMPILE_DL_LDAP) && defined(ZTS) + ZEND_TSRMLS_CACHE_UPDATE(); +#endif + + /* needed before first connect and after TLS option changes */ + LDAPG(tls_newctx) = true; + + return SUCCESS; +} +/* }}} */ + + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(ldap) { @@ -1014,6 +1029,20 @@ PHP_FUNCTION(ldap_connect) snprintf( url, urllen, "ldap://%s:" ZEND_LONG_FMT, host, port ); } +#ifdef LDAP_OPT_X_TLS_NEWCTX + if (LDAPG(tls_newctx) && url && !strncmp(url, "ldaps:", 6)) { + int val = 0; + + /* ensure all pending TLS options are applied in a new context */ + if (ldap_set_option(NULL, LDAP_OPT_X_TLS_NEWCTX, &val) != LDAP_OPT_SUCCESS) { + zval_ptr_dtor(return_value); + php_error_docref(NULL, E_WARNING, "Could not create new security context"); + RETURN_FALSE; + } + LDAPG(tls_newctx) = false; + } +#endif + #ifdef LDAP_API_FEATURE_X_OPENLDAP /* ldap_init() is deprecated, use ldap_initialize() instead. */ @@ -2316,12 +2345,12 @@ static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper, int ext) SEPARATE_ARRAY(attribute_values); uint32_t num_values = zend_hash_num_elements(Z_ARRVAL_P(attribute_values)); if (num_values == 0) { - zend_argument_value_error(3, "list of attribute values must not be empty"); + zend_argument_value_error(3, "attribute \"%s\" must be a non-empty list of attribute values", ZSTR_VAL(attribute)); RETVAL_FALSE; goto cleanup; } if (!php_ldap_is_numerically_indexed_array(Z_ARRVAL_P(attribute_values))) { - zend_argument_value_error(3, "must be an array of attribute values with numeric keys"); + zend_argument_value_error(3, "attribute \"%s\" must be an array of attribute values with numeric keys", ZSTR_VAL(attribute)); RETVAL_FALSE; goto cleanup; } @@ -2730,7 +2759,7 @@ PHP_FUNCTION(ldap_modify_batch) /* for each modification */ zend_ulong modification_index = 0; - ZEND_HASH_FOREACH_NUM_KEY_VAL(modifications, modification_index, modification_zv) { + ZEND_HASH_FOREACH_VAL(modifications, modification_zv) { ldap_mods[modification_index] = safe_emalloc(1, sizeof(LDAPMod), 0); zval *attrib_zv = zend_hash_str_find_deref(Z_ARRVAL_P(modification_zv), LDAP_MODIFY_BATCH_ATTRIB, strlen(LDAP_MODIFY_BATCH_ATTRIB)); @@ -2793,6 +2822,8 @@ PHP_FUNCTION(ldap_modify_batch) /* NULL-terminate values */ ldap_mods[modification_index]->mod_bvalues[num_modification_values] = NULL; } + + modification_index++; } ZEND_HASH_FOREACH_END(); /* NULL-terminate modifications */ @@ -3141,15 +3172,7 @@ PHP_FUNCTION(ldap_set_option) } switch (option) { - /* options with int value */ - case LDAP_OPT_DEREF: - case LDAP_OPT_SIZELIMIT: - case LDAP_OPT_TIMELIMIT: - case LDAP_OPT_PROTOCOL_VERSION: - case LDAP_OPT_ERROR_NUMBER: -#ifdef LDAP_OPT_DEBUG_LEVEL - case LDAP_OPT_DEBUG_LEVEL: -#endif + /* TLS options with int value */ #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT case LDAP_OPT_X_TLS_REQUIRE_CERT: #endif @@ -3161,6 +3184,18 @@ PHP_FUNCTION(ldap_set_option) #endif #ifdef LDAP_OPT_X_TLS_PROTOCOL_MAX case LDAP_OPT_X_TLS_PROTOCOL_MAX: +#endif + /* TLS option change requires resetting TLS context */ + LDAPG(tls_newctx) = true; + ZEND_FALLTHROUGH; + /* other options with int value */ + case LDAP_OPT_DEREF: + case LDAP_OPT_SIZELIMIT: + case LDAP_OPT_TIMELIMIT: + case LDAP_OPT_PROTOCOL_VERSION: + case LDAP_OPT_ERROR_NUMBER: +#ifdef LDAP_OPT_DEBUG_LEVEL + case LDAP_OPT_DEBUG_LEVEL: #endif #ifdef LDAP_OPT_X_KEEPALIVE_IDLE case LDAP_OPT_X_KEEPALIVE_IDLE: @@ -3234,17 +3269,7 @@ PHP_FUNCTION(ldap_set_option) } } break; #endif - /* options with string value */ - case LDAP_OPT_ERROR_STRING: -#ifdef LDAP_OPT_HOST_NAME - case LDAP_OPT_HOST_NAME: -#endif -#ifdef HAVE_LDAP_SASL - case LDAP_OPT_X_SASL_MECH: - case LDAP_OPT_X_SASL_REALM: - case LDAP_OPT_X_SASL_AUTHCID: - case LDAP_OPT_X_SASL_AUTHZID: -#endif + /* TLS options with string value */ #if (LDAP_API_VERSION > 2000) case LDAP_OPT_X_TLS_CACERTDIR: case LDAP_OPT_X_TLS_CACERTFILE: @@ -3258,6 +3283,20 @@ PHP_FUNCTION(ldap_set_option) #endif #ifdef LDAP_OPT_X_TLS_DHFILE case LDAP_OPT_X_TLS_DHFILE: +#endif + /* TLS option change requires resetting TLS context */ + LDAPG(tls_newctx) = true; + ZEND_FALLTHROUGH; + /* other options with string value */ + case LDAP_OPT_ERROR_STRING: +#ifdef LDAP_OPT_HOST_NAME + case LDAP_OPT_HOST_NAME: +#endif +#ifdef HAVE_LDAP_SASL + case LDAP_OPT_X_SASL_MECH: + case LDAP_OPT_X_SASL_REALM: + case LDAP_OPT_X_SASL_AUTHCID: + case LDAP_OPT_X_SASL_AUTHZID: #endif #ifdef LDAP_OPT_MATCHED_DN case LDAP_OPT_MATCHED_DN: @@ -3675,6 +3714,9 @@ PHP_FUNCTION(ldap_start_tls) zval *link; ldap_linkdata *ld; int rc, protocol = LDAP_VERSION3; +#ifdef LDAP_OPT_X_TLS_NEWCTX + int val = 0; +#endif if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &link, ldap_link_ce) != SUCCESS) { RETURN_THROWS(); @@ -3684,13 +3726,16 @@ PHP_FUNCTION(ldap_start_tls) VERIFY_LDAP_LINK_CONNECTED(ld); if (((rc = ldap_set_option(ld->link, LDAP_OPT_PROTOCOL_VERSION, &protocol)) != LDAP_SUCCESS) || +#ifdef LDAP_OPT_X_TLS_NEWCTX + (LDAPG(tls_newctx) && (rc = ldap_set_option(ld->link, LDAP_OPT_X_TLS_NEWCTX, &val)) != LDAP_OPT_SUCCESS) || +#endif ((rc = ldap_start_tls_s(ld->link, NULL, NULL)) != LDAP_SUCCESS) ) { php_error_docref(NULL, E_WARNING,"Unable to start TLS: %s", ldap_err2string(rc)); RETURN_FALSE; - } else { - RETURN_TRUE; } + LDAPG(tls_newctx) = false; + RETURN_TRUE; } /* }}} */ #endif @@ -4213,7 +4258,7 @@ zend_module_entry ldap_module_entry = { /* {{{ */ ext_functions, PHP_MINIT(ldap), PHP_MSHUTDOWN(ldap), - NULL, + PHP_RINIT(ldap), NULL, PHP_MINFO(ldap), PHP_LDAP_VERSION, diff --git a/ext/ldap/php_ldap.h b/ext/ldap/php_ldap.h index 5581f5b7671a8..a8c4a77af8010 100644 --- a/ext/ldap/php_ldap.h +++ b/ext/ldap/php_ldap.h @@ -39,6 +39,7 @@ PHP_MINFO_FUNCTION(ldap); ZEND_BEGIN_MODULE_GLOBALS(ldap) zend_long num_links; zend_long max_links; + bool tls_newctx; /* create new TLS context before connect */ ZEND_END_MODULE_GLOBALS(ldap) #if defined(ZTS) && defined(COMPILE_DL_LDAP) diff --git a/ext/ldap/tests/ldap_add_modify_delete_programming_errors.phpt b/ext/ldap/tests/ldap_add_modify_delete_programming_errors.phpt index 879b465dfeae4..a84e068ba3ace 100644 --- a/ext/ldap/tests/ldap_add_modify_delete_programming_errors.phpt +++ b/ext/ldap/tests/ldap_add_modify_delete_programming_errors.phpt @@ -137,7 +137,7 @@ ValueError: ldap_add(): Argument #3 ($entry) must be an associative array of att ValueError: ldap_add(): Argument #3 ($entry) key must not be empty ValueError: ldap_add(): Argument #3 ($entry) key must not contain any null bytes Error: Object of class stdClass could not be converted to string -ValueError: ldap_add(): Argument #3 ($entry) list of attribute values must not be empty -ValueError: ldap_add(): Argument #3 ($entry) must be an array of attribute values with numeric keys +ValueError: ldap_add(): Argument #3 ($entry) attribute "attribute2" must be a non-empty list of attribute values +ValueError: ldap_add(): Argument #3 ($entry) attribute "attribute2" must be an array of attribute values with numeric keys TypeError: LDAP value must be of type string|int|bool, array given Error: Object of class stdClass could not be converted to string diff --git a/ext/ldap/tests/ldap_add_modify_delete_references_programming_errors.phpt b/ext/ldap/tests/ldap_add_modify_delete_references_programming_errors.phpt index 4926dbb841d0c..3ded9699f459f 100644 --- a/ext/ldap/tests/ldap_add_modify_delete_references_programming_errors.phpt +++ b/ext/ldap/tests/ldap_add_modify_delete_references_programming_errors.phpt @@ -76,6 +76,6 @@ try { ?> --EXPECT-- Error: Object of class stdClass could not be converted to string -ValueError: ldap_add(): Argument #3 ($entry) list of attribute values must not be empty +ValueError: ldap_add(): Argument #3 ($entry) attribute "attribute2" must be a non-empty list of attribute values TypeError: LDAP value must be of type string|int|bool, array given TypeError: LDAP value must be of type string|int|bool, stdClass given diff --git a/ext/ldap/tests/ldap_modify_batch_error.phpt b/ext/ldap/tests/ldap_modify_batch_error.phpt index bce62cafb2791..0ac093b4a0341 100644 --- a/ext/ldap/tests/ldap_modify_batch_error.phpt +++ b/ext/ldap/tests/ldap_modify_batch_error.phpt @@ -59,6 +59,16 @@ $mods = array( ) ); +var_dump(ldap_modify_batch($link, "dc=my-domain,$base", $mods)); + +// high key with invalid attribute type +$mods = [ + 99999 => [ + "attrib" => "weirdAttribute", + "modtype" => LDAP_MODIFY_BATCH_ADD, + "values" => ["value1"], + ], +]; var_dump(ldap_modify_batch($link, "dc=my-domain,$base", $mods)); ?> --CLEAN-- @@ -81,3 +91,6 @@ bool(false) Warning: ldap_modify_batch(): Batch Modify: Undefined attribute type in %s on line %d bool(false) + +Warning: ldap_modify_batch(): Batch Modify: Undefined attribute type in %s on line %d +bool(false) diff --git a/ext/ldap/tests/ldap_start_tls_basic.phpt b/ext/ldap/tests/ldap_start_tls_basic.phpt index 4dbdce034369f..b8816de9ac4f5 100644 --- a/ext/ldap/tests/ldap_start_tls_basic.phpt +++ b/ext/ldap/tests/ldap_start_tls_basic.phpt @@ -9,11 +9,28 @@ ldap --FILE-- --EXPECT-- +bool(false) bool(true) +bool(false) diff --git a/ext/ldap/tests/ldaps_basic.phpt b/ext/ldap/tests/ldaps_basic.phpt new file mode 100644 index 0000000000000..7a1a1383436d7 --- /dev/null +++ b/ext/ldap/tests/ldaps_basic.phpt @@ -0,0 +1,55 @@ +--TEST-- +ldap_connect() - Basic ldaps test +--EXTENSIONS-- +ldap +--XFAIL-- +Passes locally but fails on CI - need investigation (configuration ?) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(false) +bool(true) +bool(true) +bool(false) +bool(false) diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 94704d09e463e..429f04c00bc05 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -769,13 +769,18 @@ static xmlParserInputPtr php_libxml_external_entity_loader(const char *URL, is_string: resource = Z_STRVAL(retval); } else if (Z_TYPE(retval) == IS_RESOURCE) { - php_stream *stream; - php_stream_from_zval_no_verify(stream, &retval); - if (stream == NULL) { - php_libxml_ctx_error(context, - "The user entity loader callback '%s' has returned a " - "resource, but it is not a stream", - ZSTR_VAL(LIBXML(entity_loader_callback).function_handler->common.function_name)); + php_stream *stream = (php_stream*)zend_fetch_resource2_ex(&retval, NULL, php_file_le_stream(), php_file_le_pstream()); + if (UNEXPECTED(stream == NULL)) { + zval callable; + zend_get_callable_zval_from_fcc(&LIBXML(entity_loader_callback), &callable); + zend_string *callable_name = zend_get_callable_name(&callable); + zend_string *func_name = get_active_function_or_method_name(); + zend_type_error( + "%s(): The user entity loader callback \"%s\" has returned a resource, but it is not a stream", + ZSTR_VAL(func_name), ZSTR_VAL(callable_name)); + zend_string_release(func_name); + zend_string_release(callable_name); + zval_ptr_dtor(&callable); } else { /* TODO: allow storing the encoding in the stream context? */ xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; diff --git a/ext/libxml/mime_sniff.c b/ext/libxml/mime_sniff.c index 79ce1dc46b5e0..0ca032f9b795e 100644 --- a/ext/libxml/mime_sniff.c +++ b/ext/libxml/mime_sniff.c @@ -308,11 +308,21 @@ PHP_LIBXML_API zend_string *php_libxml_sniff_charset_from_stream(const php_strea if (Z_TYPE(s->wrapperdata) == IS_ARRAY) { zval *header; - ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(s->wrapperdata), header) { - const char buf[] = "Content-Type:"; - if (Z_TYPE_P(header) == IS_STRING && - !zend_binary_strncasecmp(Z_STRVAL_P(header), Z_STRLEN_P(header), buf, sizeof(buf)-1, sizeof(buf)-1)) { - return php_libxml_sniff_charset_from_string(Z_STRVAL_P(header) + sizeof(buf) - 1, Z_STRVAL_P(header) + Z_STRLEN_P(header)); + /* Scan backwards: The header array might contain the headers for multiple responses, if + * a redirect was followed. + */ + ZEND_HASH_REVERSE_FOREACH_VAL_IND(Z_ARRVAL(s->wrapperdata), header) { + if (Z_TYPE_P(header) == IS_STRING) { + /* If no colon is found in the header, we assume it's the HTTP status line and bail out. */ + char *colon = memchr(Z_STRVAL_P(header), ':', Z_STRLEN_P(header)); + char *space = memchr(Z_STRVAL_P(header), ' ', Z_STRLEN_P(header)); + if (colon == NULL || space < colon) { + return NULL; + } + + if (zend_string_starts_with_literal_ci(Z_STR_P(header), "content-type:")) { + return php_libxml_sniff_charset_from_string(Z_STRVAL_P(header) + strlen("content-type:"), Z_STRVAL_P(header) + Z_STRLEN_P(header)); + } } } ZEND_HASH_FOREACH_END(); } diff --git a/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt b/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt index 20e783e279848..3dca273d5959c 100644 --- a/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt +++ b/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt @@ -37,4 +37,4 @@ try { ?> --EXPECT-- -string(73) "DOMDocument::validate(): supplied resource is not a valid stream resource" +string(122) "DOMDocument::validate(): The user entity loader callback "Handler::handle" has returned a resource, but it is not a stream" diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_encoding.c b/ext/mbstring/libmbfl/mbfl/mbfl_encoding.c index 6e44f68b85790..63ca5bc6a2e75 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_encoding.c +++ b/ext/mbstring/libmbfl/mbfl/mbfl_encoding.c @@ -31,7 +31,7 @@ #include "libmbfl/config.h" #ifdef HAVE_STRINGS_H - /* For strcasecmp */ + /* For strncasecmp */ #include #endif @@ -54,13 +54,6 @@ #include "filters/mbfilter_htmlent.h" #include "filters/mbfilter_singlebyte.h" -#ifndef HAVE_STRCASECMP -#ifdef HAVE_STRICMP -#define strcasecmp stricmp -#endif -#endif - - static const mbfl_encoding *mbfl_encoding_ptr_list[] = { &mbfl_encoding_base64, &mbfl_encoding_uuencode, diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index d38e2193d6379..7f0cbaeb346ee 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -1573,7 +1573,9 @@ PHP_FUNCTION(mb_output_handler) char *mimetype = NULL; /* Analyze mime type */ - if (SG(sapi_headers).mimetype && _php_mb_match_regex(MBSTRG(http_output_conv_mimetypes), SG(sapi_headers).mimetype, strlen(SG(sapi_headers).mimetype))) { + if (SG(sapi_headers).mimetype + && MBSTRG(http_output_conv_mimetypes) + && _php_mb_match_regex(MBSTRG(http_output_conv_mimetypes), SG(sapi_headers).mimetype, strlen(SG(sapi_headers).mimetype))) { char *s; if ((s = strchr(SG(sapi_headers).mimetype, ';')) == NULL) { mimetype = estrdup(SG(sapi_headers).mimetype); diff --git a/ext/mbstring/tests/gh17989.phpt b/ext/mbstring/tests/gh17989.phpt new file mode 100644 index 0000000000000..40efd5866c171 --- /dev/null +++ b/ext/mbstring/tests/gh17989.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-17989 (mb_output_handler crash with unset http_output_conv_mimetypes) +--EXTENSIONS-- +mbstring +--INI-- +mbstring.http_output_conv_mimetypes= +--FILE-- + +--EXPECT-- +set mime type via this echo +hi diff --git a/ext/mysqli/tests/bug73462.phpt b/ext/mysqli/tests/bug73462.phpt index 15d971bee9971..7a2f126cedde3 100644 --- a/ext/mysqli/tests/bug73462.phpt +++ b/ext/mysqli/tests/bug73462.phpt @@ -5,13 +5,6 @@ mysqli --SKIPIF-- --FILE-- query("SHOW STATUS LIKE 'Connections'"); + $result = $mysql_1->query("SELECT CONNECTION_ID()"); $c1 = $result->fetch_row(); $result->free(); $mysql_1->close(); @@ -35,7 +28,7 @@ if (gethostname() == "php-ci-ppc64be") { /* Re-use persistent connection */ $mysql_3 = new mysqli('p:'.$host, $user, $passwd, $db, $port); $error = mysqli_connect_errno(); - $result = $mysql_3->query("SHOW STATUS LIKE 'Connections'"); + $result = $mysql_3->query("SELECT CONNECTION_ID()"); $c3 = $result->fetch_row(); $result->free(); $mysql_3->close(); diff --git a/ext/mysqli/tests/fetch/mysqli_fetch_all_data_types_variation.phpt b/ext/mysqli/tests/fetch/mysqli_fetch_all_data_types_variation.phpt index 69fc427001fd0..594980ec0f829 100644 --- a/ext/mysqli/tests/fetch/mysqli_fetch_all_data_types_variation.phpt +++ b/ext/mysqli/tests/fetch/mysqli_fetch_all_data_types_variation.phpt @@ -122,22 +122,27 @@ func_mysqli_fetch_all($link, $engine, "DECIMAL(10,2)", "99999999.99", "99999999. func_mysqli_fetch_all($link, $engine, "DECIMAL(10,2)", NULL, NULL, 400); // don't care about date() strict TZ warnings... -func_mysqli_fetch_all($link, $engine, "DATE", @date('Y-m-d'), @date('Y-m-d'), 410); -func_mysqli_fetch_all($link, $engine, "DATE NOT NULL", @date('Y-m-d'), @date('Y-m-d'), 420); +$date = @date('Y-m-d'); +$datetime = @date('Y-m-d H:i:s'); +$time = @date('H:i:s'); +$year = @date('Y'); + +func_mysqli_fetch_all($link, $engine, "DATE", $date, $date, 410); +func_mysqli_fetch_all($link, $engine, "DATE NOT NULL", $date, $date, 420); func_mysqli_fetch_all($link, $engine, "DATE", NULL, NULL, 430); -func_mysqli_fetch_all($link, $engine, "DATETIME", @date('Y-m-d H:i:s'), @date('Y-m-d H:i:s'), 440); -func_mysqli_fetch_all($link, $engine, "DATETIME NOT NULL", @date('Y-m-d H:i:s'), @date('Y-m-d H:i:s'), 450); +func_mysqli_fetch_all($link, $engine, "DATETIME", $datetime, $datetime, 440); +func_mysqli_fetch_all($link, $engine, "DATETIME NOT NULL", $datetime, $datetime, 450); func_mysqli_fetch_all($link, $engine, "DATETIME", NULL, NULL, 460); -func_mysqli_fetch_all($link, $engine, "TIMESTAMP", @date('Y-m-d H:i:s'), @date('Y-m-d H:i:s'), 470); +func_mysqli_fetch_all($link, $engine, "TIMESTAMP", $datetime, $datetime, 470); -func_mysqli_fetch_all($link, $engine, "TIME", @date('H:i:s'), @date('H:i:s'), 480); -func_mysqli_fetch_all($link, $engine, "TIME NOT NULL", @date('H:i:s'), @date('H:i:s'), 490); +func_mysqli_fetch_all($link, $engine, "TIME", $time, $time, 480); +func_mysqli_fetch_all($link, $engine, "TIME NOT NULL", $time, $time, 490); func_mysqli_fetch_all($link, $engine, "TIME", NULL, NULL, 500); -func_mysqli_fetch_all($link, $engine, "YEAR", @date('Y'), @date('Y'), 510); -func_mysqli_fetch_all($link, $engine, "YEAR NOT NULL", @date('Y'), @date('Y'), 520); +func_mysqli_fetch_all($link, $engine, "YEAR", $year, $year, 510); +func_mysqli_fetch_all($link, $engine, "YEAR NOT NULL", $year, $year, 520); func_mysqli_fetch_all($link, $engine, "YEAR", NULL, NULL, 530); $string255 = func_mysqli_fetch_array_make_string(255); diff --git a/ext/mysqlnd/mysqlnd_auth.c b/ext/mysqlnd/mysqlnd_auth.c index 3a30b1458dea0..b8a23f87c663e 100644 --- a/ext/mysqlnd/mysqlnd_auth.c +++ b/ext/mysqlnd/mysqlnd_auth.c @@ -487,10 +487,6 @@ mysqlnd_auth_change_user(MYSQLND_CONN_DATA * const conn, } } if (ret == PASS) { - ZEND_ASSERT(conn->username.s != user && conn->password.s != passwd); - mysqlnd_set_persistent_string(&conn->username, user, user_len, conn->persistent); - mysqlnd_set_persistent_string(&conn->password, passwd, passwd_len, conn->persistent); - mysqlnd_set_string(&conn->last_message, NULL, 0); UPSERT_STATUS_RESET(conn->upsert_status); /* set charset for old servers */ diff --git a/ext/mysqlnd/mysqlnd_commands.c b/ext/mysqlnd/mysqlnd_commands.c index 27a5f13a30746..52731425e1808 100644 --- a/ext/mysqlnd/mysqlnd_commands.c +++ b/ext/mysqlnd/mysqlnd_commands.c @@ -107,9 +107,6 @@ MYSQLND_METHOD(mysqlnd_command, init_db)(MYSQLND_CONN_DATA * const conn, const M a protocol of giving back -1. Thus we have to follow it :( */ UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); - if (ret == PASS) { - mysqlnd_set_persistent_string(&conn->connect_or_select_db, db.s, db.l, conn->persistent); - } DBG_RETURN(ret); } diff --git a/ext/mysqlnd/mysqlnd_connection.c b/ext/mysqlnd/mysqlnd_connection.c index 2787b32931747..42acb258665bc 100644 --- a/ext/mysqlnd/mysqlnd_connection.c +++ b/ext/mysqlnd/mysqlnd_connection.c @@ -282,11 +282,6 @@ MYSQLND_METHOD(mysqlnd_conn_data, free_contents)(MYSQLND_CONN_DATA * conn) DBG_INF("Freeing memory of members"); - mysqlnd_set_persistent_string(&conn->hostname, NULL, 0, pers); - mysqlnd_set_persistent_string(&conn->username, NULL, 0, pers); - mysqlnd_set_persistent_string(&conn->password, NULL, 0, pers); - mysqlnd_set_persistent_string(&conn->connect_or_select_db, NULL, 0, pers); - mysqlnd_set_persistent_string(&conn->unix_socket, NULL, 0, pers); DBG_INF_FMT("scheme=%s", conn->scheme.s); mysqlnd_set_persistent_string(&conn->scheme, NULL, 0, pers); @@ -658,22 +653,16 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, if (transport.s) { mnd_sprintf_free(transport.s); transport.s = NULL; - } - - if (!conn->scheme.s) { + } else { goto err; /* OOM */ } - mysqlnd_set_persistent_string(&conn->username, username.s, username.l, conn->persistent); - mysqlnd_set_persistent_string(&conn->password, username.s, password.l, conn->persistent); conn->port = port; - mysqlnd_set_persistent_string(&conn->connect_or_select_db, database.s, database.l, conn->persistent); if (!unix_socket && !named_pipe) { - mysqlnd_set_persistent_string(&conn->hostname, hostname.s, hostname.l, conn->persistent); { char *p; - mnd_sprintf(&p, 0, "%s via TCP/IP", conn->hostname.s); + mnd_sprintf(&p, 0, "%s via TCP/IP", hostname.s); if (!p) { SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ @@ -682,12 +671,11 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, mnd_sprintf_free(p); } } else { - conn->unix_socket.s = mnd_pestrdup(socket_or_pipe.s, conn->persistent); if (unix_socket) { conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent); } else if (named_pipe) { char *p; - mnd_sprintf(&p, 0, "%s via named pipe", conn->unix_socket.s); + mnd_sprintf(&p, 0, "%s via named pipe", socket_or_pipe.s); if (!p) { SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ @@ -697,11 +685,10 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, } else { php_error_docref(NULL, E_WARNING, "Impossible. Should be either socket or a pipe. Report a bug!"); } - if (!conn->unix_socket.s || !conn->host_info) { + if (!socket_or_pipe.s || !conn->host_info) { SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ } - conn->unix_socket.l = strlen(conn->unix_socket.s); } SET_EMPTY_ERROR(conn->error_info); diff --git a/ext/mysqlnd/mysqlnd_statistics.c b/ext/mysqlnd/mysqlnd_statistics.c index c6f7b2bab5b72..0d94303ea3669 100644 --- a/ext/mysqlnd/mysqlnd_statistics.c +++ b/ext/mysqlnd/mysqlnd_statistics.c @@ -214,8 +214,8 @@ mysqlnd_fill_stats_hash(const MYSQLND_STATS * const stats, const MYSQLND_STRING PHPAPI void mysqlnd_stats_init(MYSQLND_STATS ** stats, const size_t statistic_count, const bool persistent) { - *stats = pecalloc(1, sizeof(MYSQLND_STATS), persistent); - (*stats)->values = pecalloc(statistic_count, sizeof(uint64_t), persistent); + size_t size = zend_safe_address_guarded(statistic_count, sizeof(*(*stats)->values), sizeof(**stats)); + *stats = pecalloc(1, size, persistent); (*stats)->count = statistic_count; #ifdef ZTS (*stats)->LOCK_access = tsrm_mutex_alloc(); @@ -231,7 +231,6 @@ mysqlnd_stats_end(MYSQLND_STATS * stats, const bool persistent) #ifdef ZTS tsrm_mutex_free(stats->LOCK_access); #endif - pefree(stats->values, persistent); /* mnd_free will reference LOCK_access and crash...*/ pefree(stats, persistent); } diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index cf99ac706239c..9cbbf4a64f144 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -297,11 +297,11 @@ typedef struct st_mysqlnd_stats MYSQLND_STATS; struct st_mysqlnd_stats { - uint64_t *values; size_t count; #ifdef ZTS MUTEX_T LOCK_access; #endif + uint64_t values[] ZEND_ELEMENT_COUNT(count); }; @@ -890,10 +890,6 @@ struct st_mysqlnd_connection_data MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * payload_decoder_factory; /* Information related */ - MYSQLND_STRING hostname; - MYSQLND_STRING unix_socket; - MYSQLND_STRING username; - MYSQLND_STRING password; MYSQLND_STRING scheme; uint64_t thread_id; char *server_version; @@ -901,7 +897,6 @@ struct st_mysqlnd_connection_data MYSQLND_STRING authentication_plugin_data; const MYSQLND_CHARSET *charset; const MYSQLND_CHARSET *greet_charset; - MYSQLND_STRING connect_or_select_db; MYSQLND_INFILE infile; unsigned int protocol_version; unsigned int port; diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index df5cfcfdfd59e..704846c4a860f 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -626,7 +626,7 @@ static inline void accel_copy_permanent_list_types( zend_new_interned_string_func_t new_interned_string, zend_type type) { zend_type *single_type; - ZEND_TYPE_FOREACH(type, single_type) { + ZEND_TYPE_FOREACH_MUTABLE(type, single_type) { if (ZEND_TYPE_HAS_LIST(*single_type)) { ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(*single_type)); accel_copy_permanent_list_types(new_interned_string, *single_type); @@ -3864,6 +3864,11 @@ static bool preload_try_resolve_constants(zend_class_entry *ce) ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) { val = &c->value; if (Z_TYPE_P(val) == IS_CONSTANT_AST) { + /* For deprecated constants, we need to flag the zval for recursion + * detection. Make sure the zval is separated out of shm. */ + if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED) { + ok = false; + } if (EXPECTED(zend_update_class_constant(c, key, c->ce) == SUCCESS)) { was_changed = changed = true; } else { @@ -3879,9 +3884,13 @@ static bool preload_try_resolve_constants(zend_class_entry *ce) bool resolved = true; for (i = 0; i < ce->default_properties_count; i++) { - val = &ce->default_properties_table[i]; + zend_property_info *prop = ce->properties_info_table[i]; + if (!prop) { + continue; + } + + val = &ce->default_properties_table[OBJ_PROP_TO_NUM(prop->offset)]; if (Z_TYPE_P(val) == IS_CONSTANT_AST) { - zend_property_info *prop = ce->properties_info_table[i]; if (UNEXPECTED(zval_update_constant_ex(val, prop->ce) != SUCCESS)) { resolved = ok = false; } @@ -4796,6 +4805,11 @@ static zend_result accel_finish_startup_preload(bool in_child) EG(class_table) = NULL; EG(function_table) = NULL; PG(report_memleaks) = orig_report_memleaks; +#ifdef ZTS + /* Reset the virtual CWD state back to the original state created by virtual_cwd_startup(). + * This is necessary because the normal startup code assumes the CWD state is active. */ + virtual_cwd_activate(); +#endif } else { zend_shared_alloc_unlock(); ret = FAILURE; diff --git a/ext/opcache/jit/ir/ir.c b/ext/opcache/jit/ir/ir.c index 2721de4a6e006..d9f7e3d0f7836 100644 --- a/ext/opcache/jit/ir/ir.c +++ b/ext/opcache/jit/ir/ir.c @@ -2413,10 +2413,18 @@ static ir_ref _ir_fold_condition(ir_ctx *ctx, ir_ref ref) if (IR_IS_TYPE_INT(op2_insn->type) && op2_insn->val.u64 == 0) { ref = insn->op1; insn = &ctx->ir_base[ref]; + if (insn->op == IR_ALLOCA || insn->op == IR_VADDR) { + return IR_TRUE; + } } } else if (insn->op == IR_EQ && insn->op2 == IR_TRUE) { ref = insn->op1; insn = &ctx->ir_base[ref]; + } else if (insn->op == IR_EQ && insn->op2 == IR_NULL) { + ir_insn *op1_insn = &ctx->ir_base[insn->op1]; + if (op1_insn->op == IR_ALLOCA || op1_insn->op == IR_VADDR) { + return IR_FALSE; + } } // while (insn->op == IR_SEXT || insn->op == IR_ZEXT || insn->op == IR_BITCAST) { // ref = insn->op1; diff --git a/ext/opcache/jit/ir/ir_fold.h b/ext/opcache/jit/ir/ir_fold.h index 6f0bfea47820d..78f3ca0c01e5f 100644 --- a/ext/opcache/jit/ir/ir_fold.h +++ b/ext/opcache/jit/ir/ir_fold.h @@ -1464,7 +1464,9 @@ IR_FOLD(EQ(SEXT, C_I32)) IR_FOLD(EQ(SEXT, C_I64)) IR_FOLD(EQ(SEXT, C_ADDR)) { - if (op2_insn->val.u64 == 0 && ctx->ir_base[op1_insn->op1].type == IR_BOOL) { + if (ctx->use_lists && ctx->use_lists[op1_insn->op1].count != 1) { + /* pass */ + } else if (op2_insn->val.u64 == 0 && ctx->ir_base[op1_insn->op1].type == IR_BOOL) { opt = IR_OPT(IR_NOT, IR_BOOL); op1 = op1_insn->op1; op2 = IR_UNUSED; @@ -1509,7 +1511,9 @@ IR_FOLD(NE(SEXT, C_I32)) IR_FOLD(NE(SEXT, C_I64)) IR_FOLD(NE(SEXT, C_ADDR)) { - if (op2_insn->val.u64 == 0 && ctx->ir_base[op1_insn->op1].type == IR_BOOL) { + if (ctx->use_lists && ctx->use_lists[op1_insn->op1].count != 1) { + /* pass */ + } else if (op2_insn->val.u64 == 0 && ctx->ir_base[op1_insn->op1].type == IR_BOOL) { IR_FOLD_COPY(op1_insn->op1); } else { ir_type type = ctx->ir_base[op1_insn->op1].type; @@ -1855,8 +1859,39 @@ IR_FOLD(SUB(ADD, ADD)) } // IR_FOLD(SUB(NEG, CONST)) TODO: -a - b => -b - a -// IR_FOLD(MUL(NEG, CONST)) TODO: -a * b => a * -b -// IR_FOLD(DIV(NEG, CONST)) TODO: -a / b => a / -b + +IR_FOLD(MUL(NEG, C_I8)) +IR_FOLD(MUL(NEG, C_I16)) +IR_FOLD(MUL(NEG, C_I32)) +IR_FOLD(MUL(NEG, C_I64)) +IR_FOLD(DIV(NEG, C_I8)) +IR_FOLD(DIV(NEG, C_I16)) +IR_FOLD(DIV(NEG, C_I32)) +IR_FOLD(DIV(NEG, C_I64)) +{ + op1 = op1_insn->op1; + val.i64 = -op2_insn->val.i64; + op2 = ir_const(ctx, val, op2_insn->type); + IR_FOLD_RESTART; +} + +IR_FOLD(MUL(NEG, C_FLOAT)) +IR_FOLD(DIV(NEG, C_FLOAT)) +{ + op1 = op1_insn->op1; + val.f = -op2_insn->val.f; + op2 = ir_const(ctx, val, op2_insn->type); + IR_FOLD_RESTART; +} + +IR_FOLD(MUL(NEG, C_DOUBLE)) +IR_FOLD(DIV(NEG, C_DOUBLE)) +{ + op1 = op1_insn->op1; + val.d = -op2_insn->val.d; + op2 = ir_const(ctx, val, op2_insn->type); + IR_FOLD_RESTART; +} IR_FOLD(MUL(_, C_U8)) IR_FOLD(MUL(_, C_U16)) @@ -2464,6 +2499,17 @@ IR_FOLD(SEXT(AND)) IR_FOLD_NEXT; } +IR_FOLD(SEXT(SHR)) +{ + if (IR_IS_CONST_REF(op1_insn->op2) + && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op) + && ctx->ir_base[op1_insn->op2].val.u64 != 0) { + opt = IR_OPT(IR_ZEXT, IR_OPT_TYPE(opt)); + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} + IR_FOLD(TRUNC(AND)) { if (IR_IS_CONST_REF(op1_insn->op2)) { @@ -2490,6 +2536,44 @@ IR_FOLD(TRUNC(AND)) IR_FOLD_NEXT; } +IR_FOLD(AND(ZEXT, C_I16)) +IR_FOLD(AND(ZEXT, C_U16)) +IR_FOLD(AND(ZEXT, C_I32)) +IR_FOLD(AND(ZEXT, C_U32)) +IR_FOLD(AND(ZEXT, C_I64)) +IR_FOLD(AND(ZEXT, C_U64)) +IR_FOLD(AND(ZEXT, C_ADDR)) +{ + ir_type src_size = ir_type_size[ctx->ir_base[op1_insn->op1].type]; + + if ((src_size == 1 && op2_insn->val.u64 == 0xff) + || (src_size == 2 && op2_insn->val.u64 == 0xffff) + || (src_size == 4 && op2_insn->val.u64 == 0xffffffff)) { + IR_FOLD_COPY(op1); + } + IR_FOLD_NEXT; +} + +IR_FOLD(AND(SEXT, C_I16)) +IR_FOLD(AND(SEXT, C_U16)) +IR_FOLD(AND(SEXT, C_I32)) +IR_FOLD(AND(SEXT, C_U32)) +IR_FOLD(AND(SEXT, C_I64)) +IR_FOLD(AND(SEXT, C_U64)) +IR_FOLD(AND(SEXT, C_ADDR)) +{ + ir_type src_size = ir_type_size[ctx->ir_base[op1_insn->op1].type]; + + if ((src_size == 1 && op2_insn->val.u64 == 0xff) + || (src_size == 2 && op2_insn->val.u64 == 0xffff) + || (src_size == 4 && op2_insn->val.u64 == 0xffffffff)) { + opt = IR_OPT(IR_ZEXT, IR_OPT_TYPE(opt)); + op1 = op1_insn->op1; + op2 = IR_UNUSED; + IR_FOLD_RESTART; + } + IR_FOLD_NEXT; +} IR_FOLD(AND(SHR, C_I8)) IR_FOLD(AND(SHR, C_U8)) { diff --git a/ext/opcache/jit/ir/ir_gcm.c b/ext/opcache/jit/ir/ir_gcm.c index 396ba2d7f7c7b..8bd6be5d10aa0 100644 --- a/ext/opcache/jit/ir/ir_gcm.c +++ b/ext/opcache/jit/ir/ir_gcm.c @@ -413,10 +413,11 @@ static bool ir_split_partially_dead_node(ir_ctx *ctx, ir_ref ref, uint32_t b) n = ctx->use_lists[ref].refs; for (i = 0; i < clones_count; i++) { clone = clones[i].ref; - if (clones[i].use_count == 1) { + if (clones[i].use_count == 1 + && ctx->cfg_blocks[clones[i].block].loop_depth >= ctx->cfg_blocks[uses[clones[i].use].block].loop_depth) { /* TOTALLY_USEFUL block may be a head of a diamond above the real usage. * Sink it down to the real usage block. - * Clones with few uses we be sunk into the LCA block. + * Clones with few uses will be sunk into the LCA block. */ clones[i].block = uses[clones[i].use].block; } diff --git a/ext/opcache/jit/ir/ir_sccp.c b/ext/opcache/jit/ir/ir_sccp.c index b4f2257744145..8480861f91fe7 100644 --- a/ext/opcache/jit/ir/ir_sccp.c +++ b/ext/opcache/jit/ir/ir_sccp.c @@ -553,8 +553,7 @@ static IR_NEVER_INLINE void ir_sccp_analyze(ir_ctx *ctx, ir_insn *_values, ir_bi } if (!may_benefit) { IR_MAKE_BOTTOM_EX(i); - if (insn->op == IR_FP2FP || insn->op == IR_FP2INT || insn->op == IR_TRUNC - || insn->op == IR_ZEXT || insn->op == IR_SEXT || insn->op == IR_EQ || insn->op == IR_NE) { + if (insn->op == IR_FP2FP || insn->op == IR_FP2INT || insn->op == IR_TRUNC) { ir_bitqueue_add(iter_worklist, i); } } else if (!ir_sccp_fold(ctx, _values, worklist, i, insn)) { @@ -562,8 +561,7 @@ static IR_NEVER_INLINE void ir_sccp_analyze(ir_ctx *ctx, ir_insn *_values, ir_bi continue; } else if (_values[i].op == IR_BOTTOM) { insn = &ctx->ir_base[i]; - if (insn->op == IR_FP2FP || insn->op == IR_FP2INT || insn->op == IR_TRUNC - || insn->op == IR_ZEXT || insn->op == IR_SEXT || insn->op == IR_EQ || insn->op == IR_NE) { + if (insn->op == IR_FP2FP || insn->op == IR_FP2INT || insn->op == IR_TRUNC) { ir_bitqueue_add(iter_worklist, i); } } @@ -571,7 +569,7 @@ static IR_NEVER_INLINE void ir_sccp_analyze(ir_ctx *ctx, ir_insn *_values, ir_bi IR_MAKE_BOTTOM_EX(i); } } else if (flags & IR_OP_FLAG_BB_START) { - if (insn->op == IR_MERGE || insn->op == IR_BEGIN) { + if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_BEGIN) { ir_bitqueue_add(iter_worklist, i); } if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) { @@ -919,163 +917,128 @@ static void ir_sccp_remove_if(ir_ctx *ctx, ir_insn *_values, ir_ref ref, ir_ref } } -static void ir_sccp_remove_unfeasible_merge_inputs(ir_ctx *ctx, ir_insn *_values, ir_ref ref, ir_ref unfeasible_inputs) +static bool ir_sccp_remove_unfeasible_merge_inputs(ir_ctx *ctx, ir_ref ref, ir_insn *insn, ir_bitqueue *worklist) { - ir_ref i, j, n, k, *p, use; - ir_insn *insn, *use_insn; + ir_ref old_merge_inputs, new_merge_inputs, i, *p; ir_use_list *use_list; ir_bitset life_inputs; + ir_bitset_base_t holder = 0; - insn = &ctx->ir_base[ref]; IR_ASSERT(insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN); - n = insn->inputs_count; - if (n - unfeasible_inputs == 1) { - /* remove MERGE completely */ - for (j = 1; j <= n; j++) { - ir_ref input = ir_insn_op(insn, j); - if (input && IR_IS_REACHABLE(input)) { - ir_insn *input_insn = &ctx->ir_base[input]; - - IR_ASSERT(input_insn->op == IR_END || input_insn->op == IR_LOOP_END|| - input_insn->op == IR_IJMP || input_insn->op == IR_UNREACHABLE); - if (input_insn->op == IR_END || input_insn->op == IR_LOOP_END) { - ir_ref prev, next = IR_UNUSED; - ir_insn *next_insn = NULL; - - prev = input_insn->op1; - use_list = &ctx->use_lists[ref]; - if (use_list->count == 1) { - next = ctx->use_edges[use_list->refs]; - next_insn = &ctx->ir_base[next]; - } else { - k = 0; - p = &ctx->use_edges[use_list->refs]; - while (k < use_list->count) { - use = *p; - use_insn = &ctx->ir_base[use]; -#if IR_COMBO_COPY_PROPAGATION - IR_ASSERT((use_insn->op != IR_PHI) && "PHI must be already removed"); -#else - if (use_insn->op == IR_PHI) { - /* Convert PHI into COPY */ - ir_ref i, n = use_insn->inputs_count; - - for (i = 2; i <= n; i++) { - if (i != j + 1) { - ir_ref from = ir_insn_op(use_insn, i); - if (from > 0) { - ir_use_list_remove_one(ctx, from, use); - } - ir_insn_set_op(use_insn, i, IR_UNUSED); - } - } - use_insn->optx = IR_OPTX(IR_COPY, use_insn->type, 1); - use_insn->op1 = ir_insn_op(use_insn, j + 1); - ir_insn_set_op(use_insn, j + 1, IR_UNUSED); - ir_use_list_remove_one(ctx, ref, use); - p = &ctx->use_edges[use_list->refs + k]; - continue; - } -#endif - if (ir_op_flags[use_insn->op] & IR_OP_FLAG_CONTROL) { - IR_ASSERT(!next); - next = use; - next_insn = use_insn; - } else if (use_insn->op != IR_NOP) { - IR_ASSERT(use_insn->op1 == ref); - IR_ASSERT(use_insn->op == IR_VAR); - ir_ref region = prev; - while (!IR_IS_BB_START(ctx->ir_base[region].op)) { - region = ctx->ir_base[region].op1; - } - use_insn->op1 = region; - ir_use_list_add(ctx, region, use); - p = &ctx->use_edges[use_list->refs + k]; - } - k++; - p++; - } - } - IR_ASSERT(prev && next); - if (prev < next) { - /* remove MERGE and input END from double linked control list */ - next_insn->op1 = prev; - ir_use_list_replace_one(ctx, prev, input, next); - /* remove MERGE and input END instructions */ - ir_sccp_make_nop(ctx, ref); - ir_sccp_make_nop(ctx, input); - } else { - for (i = 2; i <= n; i++) { - ir_insn_set_op(insn, i, IR_UNUSED); - } - insn->op = IR_BEGIN; - insn->op1 = input; - input_insn->op = IR_END; - } - break; - } else { - for (i = 2; i <= n; i++) { - ir_insn_set_op(insn, i, IR_UNUSED); - } - insn->op = IR_BEGIN; - insn->op1 = input; - } + old_merge_inputs = insn->inputs_count; + new_merge_inputs = 0; + life_inputs = (old_merge_inputs < IR_BITSET_BITS) ? &holder : ir_bitset_malloc(old_merge_inputs + 1); + + for (i = 1; i <= old_merge_inputs; i++) { + ir_ref input = ir_insn_op(insn, i); + + if (input) { + new_merge_inputs++; + if (new_merge_inputs != i) { + ir_insn_set_op(insn, new_merge_inputs, input); } + ir_bitset_incl(life_inputs, i); } - } else { - n = insn->inputs_count; - i = 1; - life_inputs = ir_bitset_malloc(n + 1); - for (j = 1; j <= n; j++) { - ir_ref input = ir_insn_op(insn, j); + } - if (input) { - if (i != j) { - ir_insn_set_op(insn, i, input); - } - ir_bitset_incl(life_inputs, j); - i++; - } + if (new_merge_inputs == old_merge_inputs) { + /* All inputs are feasible */ + if (life_inputs != &holder) { + ir_mem_free(life_inputs); } - j = i; - while (j <= n) { - ir_insn_set_op(insn, j, IR_UNUSED); - j++; + return 0; + } + + for (i = new_merge_inputs + 1; i <= old_merge_inputs; i++) { + ir_insn_set_op(insn, i, IR_UNUSED); + } + + if (new_merge_inputs <= 1) { +#if 0 + if (new_merge_inputs == 1 + && insn->op == IR_LOOP_BEGIN + && insn->op1 > ref) { // TODO: check dominance instead of order + /* dead loop */ + ir_use_list_remove_one(ctx, insn->op1, ref); + insn->op1 = IR_UNUSED; + new_merge_inputs = 0; } - i--; - insn->inputs_count = i; +#endif + insn->optx = IR_OPTX(IR_BEGIN, IR_VOID, 1); + ir_bitqueue_add(worklist, ref); + } else { + insn->inputs_count = new_merge_inputs; + } - n++; - use_list = &ctx->use_lists[ref]; - if (use_list->count > 1) { - for (k = use_list->count, p = &ctx->use_edges[use_list->refs]; k > 0; p++, k--) { - use = *p; - use_insn = &ctx->ir_base[use]; - if (use_insn->op == IR_PHI) { - i = 2; - for (j = 2; j <= n; j++) { - ir_ref input = ir_insn_op(use_insn, j); - - if (ir_bitset_in(life_inputs, j - 1)) { - IR_ASSERT(input); - if (i != j) { - ir_insn_set_op(use_insn, i, input); - } - i++; - } else if (!IR_IS_CONST_REF(input)) { - ir_use_list_remove_one(ctx, input, use); + /* Update PHIs */ + use_list = &ctx->use_lists[ref]; + if (use_list->count > 1) { + ir_ref use_count = 0; + ir_ref *q; + + for (i = 0, p = q = &ctx->use_edges[use_list->refs]; i < use_list->count; p++, i++) { + ir_ref use = *p; + ir_insn *use_insn = &ctx->ir_base[use]; + + if (use_insn->op == IR_PHI) { + ir_ref j, k; + + /* compress PHI */ + for (j = k = 1; j <= old_merge_inputs; j++) { + ir_ref input = ir_insn_op(use_insn, j + 1); + + if (ir_bitset_in(life_inputs, j)) { + IR_ASSERT(input); + if (k != j) { + ir_insn_set_op(use_insn, k + 1, input); } + k++; + } else if (input > 0) { + ir_use_list_remove_one(ctx, input, use); } - while (i <= n) { - ir_insn_set_op(use_insn, i, IR_UNUSED); - i++; - } - use_insn->inputs_count = insn->inputs_count + 1; + } + while (k <= old_merge_inputs) { + k++; + ir_insn_set_op(use_insn, k, IR_UNUSED); + } + + if (new_merge_inputs == 0) { + /* remove PHI */ +#if 0 + use_insn->op1 = IR_UNUSED; + ir_iter_remove_insn(ctx, use, worklist); +#else + IR_ASSERT(0); +#endif + continue; + } else if (new_merge_inputs == 1) { + /* replace PHI by COPY */ + use_insn->optx = IR_OPTX(IR_COPY, use_insn->type, 1); + use_insn->op1 = use_insn->op2; + use_insn->op2 = IR_UNUSED; + ir_bitqueue_add(worklist, use); + continue; + } else { + use_insn->inputs_count = new_merge_inputs + 1; } } + if (p != q) { + *q = use; + } + q++; + use_count++; + } + for (i = use_count; i < use_list->count; q++, i++) { + *q = IR_UNUSED; } + use_list->count = use_count; + } + + if (life_inputs != &holder) { ir_mem_free(life_inputs); } + + return 1; } static IR_NEVER_INLINE void ir_sccp_transform(ir_ctx *ctx, ir_insn *_values, ir_bitqueue *worklist, ir_bitqueue *iter_worklist) @@ -1105,7 +1068,7 @@ static IR_NEVER_INLINE void ir_sccp_transform(ir_ctx *ctx, ir_insn *_values, ir_ if (insn->op == IR_NOP) { /* already removed */ } else if (ir_op_flags[insn->op] & (IR_OP_FLAG_DATA|IR_OP_FLAG_MEM)) { - if (insn->op != IR_PARAM && (insn->op != IR_VAR || _values[insn->op1].op == IR_TOP)) { + if (insn->op != IR_PARAM) { ir_sccp_remove_insn(ctx, _values, i, iter_worklist); } } else { @@ -1137,7 +1100,7 @@ static IR_NEVER_INLINE void ir_sccp_transform(ir_ctx *ctx, ir_insn *_values, ir_ while ((i = ir_bitqueue_pop(worklist)) >= 0) { IR_ASSERT(_values[i].op == IR_MERGE); - ir_sccp_remove_unfeasible_merge_inputs(ctx, _values, i, _values[i].op1); + ir_sccp_remove_unfeasible_merge_inputs(ctx, i, &ctx->ir_base[i], iter_worklist); } } @@ -1261,7 +1224,7 @@ static void ir_iter_replace_insn(ir_ctx *ctx, ir_ref ref, ir_ref new_ref, ir_bit ir_bitqueue_add(worklist, input); } else if (ctx->ir_base[input].op == IR_PHI && ctx->use_lists[input].count == 1) { /* try to optimize PHI into ABS/MIN/MAX/COND */ - ir_bitqueue_add(worklist, input); + ir_bitqueue_add(worklist, ctx->ir_base[input].op1); } } } @@ -1554,7 +1517,7 @@ static bool ir_may_promote_f2d(ir_ctx *ctx, ir_ref ref) return 0; } -static ir_ref ir_promote_d2f(ir_ctx *ctx, ir_ref ref, ir_ref use) +static ir_ref ir_promote_d2f(ir_ctx *ctx, ir_ref ref, ir_ref use, ir_bitqueue *worklist) { ir_insn *insn = &ctx->ir_base[ref]; uint32_t count; @@ -1563,6 +1526,7 @@ static ir_ref ir_promote_d2f(ir_ctx *ctx, ir_ref ref, ir_ref use) if (IR_IS_CONST_REF(ref)) { return ir_const_float(ctx, (float)insn->val.d); } else { + ir_bitqueue_add(worklist, ref); switch (insn->op) { case IR_FP2FP: count = ctx->use_lists[ref].count; @@ -1592,7 +1556,7 @@ static ir_ref ir_promote_d2f(ir_ctx *ctx, ir_ref ref, ir_ref use) // return ref; case IR_NEG: case IR_ABS: - insn->op1 = ir_promote_d2f(ctx, insn->op1, ref); + insn->op1 = ir_promote_d2f(ctx, insn->op1, ref, worklist); insn->type = IR_FLOAT; return ref; case IR_ADD: @@ -1602,10 +1566,10 @@ static ir_ref ir_promote_d2f(ir_ctx *ctx, ir_ref ref, ir_ref use) case IR_MIN: case IR_MAX: if (insn->op1 == insn->op2) { - insn->op2 = insn->op1 = ir_promote_d2f(ctx, insn->op1, ref); + insn->op2 = insn->op1 = ir_promote_d2f(ctx, insn->op1, ref, worklist); } else { - insn->op1 = ir_promote_d2f(ctx, insn->op1, ref); - insn->op2 = ir_promote_d2f(ctx, insn->op2, ref); + insn->op1 = ir_promote_d2f(ctx, insn->op1, ref, worklist); + insn->op2 = ir_promote_d2f(ctx, insn->op2, ref, worklist); } insn->type = IR_FLOAT; return ref; @@ -1617,7 +1581,7 @@ static ir_ref ir_promote_d2f(ir_ctx *ctx, ir_ref ref, ir_ref use) return ref; } -static ir_ref ir_promote_f2d(ir_ctx *ctx, ir_ref ref, ir_ref use) +static ir_ref ir_promote_f2d(ir_ctx *ctx, ir_ref ref, ir_ref use, ir_bitqueue *worklist) { ir_insn *insn = &ctx->ir_base[ref]; uint32_t count; @@ -1627,6 +1591,7 @@ static ir_ref ir_promote_f2d(ir_ctx *ctx, ir_ref ref, ir_ref use) if (IR_IS_CONST_REF(ref)) { return ir_const_double(ctx, (double)insn->val.f); } else { + ir_bitqueue_add(worklist, ref); switch (insn->op) { case IR_FP2FP: count = ctx->use_lists[ref].count; @@ -1665,7 +1630,7 @@ static ir_ref ir_promote_f2d(ir_ctx *ctx, ir_ref ref, ir_ref use) return ref; case IR_NEG: case IR_ABS: - insn->op1 = ir_promote_f2d(ctx, insn->op1, ref); + insn->op1 = ir_promote_f2d(ctx, insn->op1, ref, worklist); insn->type = IR_DOUBLE; return ref; case IR_ADD: @@ -1675,10 +1640,10 @@ static ir_ref ir_promote_f2d(ir_ctx *ctx, ir_ref ref, ir_ref use) case IR_MIN: case IR_MAX: if (insn->op1 == insn->op2) { - insn->op2 = insn->op1 = ir_promote_f2d(ctx, insn->op1, ref); + insn->op2 = insn->op1 = ir_promote_f2d(ctx, insn->op1, ref, worklist); } else { - insn->op1 = ir_promote_f2d(ctx, insn->op1, ref); - insn->op2 = ir_promote_f2d(ctx, insn->op2, ref); + insn->op1 = ir_promote_f2d(ctx, insn->op1, ref, worklist); + insn->op2 = ir_promote_f2d(ctx, insn->op2, ref, worklist); } insn->type = IR_DOUBLE; return ref; @@ -1690,9 +1655,10 @@ static ir_ref ir_promote_f2d(ir_ctx *ctx, ir_ref ref, ir_ref use) return ref; } -static bool ir_may_promote_i2i(ir_ctx *ctx, ir_type type, ir_ref ref) +static bool ir_may_promote_trunc(ir_ctx *ctx, ir_type type, ir_ref ref) { ir_insn *insn = &ctx->ir_base[ref]; + ir_ref *p, n, input; if (IR_IS_CONST_REF(ref)) { return !IR_IS_SYM_CONST(insn->op); @@ -1700,16 +1666,16 @@ static bool ir_may_promote_i2i(ir_ctx *ctx, ir_type type, ir_ref ref) switch (insn->op) { case IR_ZEXT: case IR_SEXT: - return ctx->ir_base[insn->op1].type == type; + case IR_TRUNC: + return ctx->ir_base[insn->op1].type == type || ctx->use_lists[ref].count == 1; case IR_NEG: case IR_ABS: case IR_NOT: return ctx->use_lists[ref].count == 1 && - ir_may_promote_i2i(ctx, type, insn->op1); + ir_may_promote_trunc(ctx, type, insn->op1); case IR_ADD: case IR_SUB: case IR_MUL: -// case IR_DIV: case IR_MIN: case IR_MAX: case IR_OR: @@ -1717,8 +1683,41 @@ static bool ir_may_promote_i2i(ir_ctx *ctx, ir_type type, ir_ref ref) case IR_XOR: case IR_SHL: return ctx->use_lists[ref].count == 1 && - ir_may_promote_i2i(ctx, type, insn->op1) && - ir_may_promote_i2i(ctx, type, insn->op2); + ir_may_promote_trunc(ctx, type, insn->op1) && + ir_may_promote_trunc(ctx, type, insn->op2); +// case IR_SHR: +// case IR_SAR: +// case IR_DIV: +// case IR_MOD: +// case IR_FP2INT: +// TODO: ??? + case IR_COND: + return ctx->use_lists[ref].count == 1 && + ir_may_promote_trunc(ctx, type, insn->op2) && + ir_may_promote_trunc(ctx, type, insn->op3); + case IR_PHI: + if (ctx->use_lists[ref].count != 1) { + ir_use_list *use_list = &ctx->use_lists[ref]; + ir_ref count = 0; + + for (p = &ctx->use_edges[use_list->refs], n = use_list->count; n > 0; p++, n--) { + if (*p != ref) { + if (count) { + return 0; + } + count = 1; + } + } + } + for (p = insn->ops + 2, n = insn->inputs_count - 1; n > 0; p++, n--) { + input = *p; + if (input != ref) { + if (!ir_may_promote_trunc(ctx, type, input)) { + return 0; + } + } + } + return 1; default: break; } @@ -1726,17 +1725,35 @@ static bool ir_may_promote_i2i(ir_ctx *ctx, ir_type type, ir_ref ref) return 0; } -static ir_ref ir_promote_i2i(ir_ctx *ctx, ir_type type, ir_ref ref, ir_ref use) +static ir_ref ir_promote_i2i(ir_ctx *ctx, ir_type type, ir_ref ref, ir_ref use, ir_bitqueue *worklist) { ir_insn *insn = &ctx->ir_base[ref]; uint32_t count; + ir_ref *p, n, input; if (IR_IS_CONST_REF(ref)) { return ir_const(ctx, insn->val, type); } else { + ir_bitqueue_add(worklist, ref); switch (insn->op) { case IR_ZEXT: case IR_SEXT: + case IR_TRUNC: + if (ctx->ir_base[insn->op1].type != type) { + ir_type src_type = ctx->ir_base[insn->op1].type; + if (ir_type_size[src_type] == ir_type_size[type]) { + insn->op = IR_BITCAST; + } else if (ir_type_size[src_type] > ir_type_size[type]) { + insn->op = IR_TRUNC; + } else { + if (insn->op != IR_SEXT && insn->op != IR_ZEXT) { + insn->op = IR_IS_TYPE_SIGNED(type) ? IR_SEXT : IR_ZEXT; + } + } + insn->type = type; + return ref; + } + count = ctx->use_lists[ref].count; ir_use_list_remove_all(ctx, ref, use); if (ctx->use_lists[ref].count == 0) { @@ -1762,13 +1779,12 @@ static ir_ref ir_promote_i2i(ir_ctx *ctx, ir_type type, ir_ref ref, ir_ref use) case IR_NEG: case IR_ABS: case IR_NOT: - insn->op1 = ir_promote_i2i(ctx, type, insn->op1, ref); + insn->op1 = ir_promote_i2i(ctx, type, insn->op1, ref, worklist); insn->type = type; return ref; case IR_ADD: case IR_SUB: case IR_MUL: -// case IR_DIV: case IR_MIN: case IR_MAX: case IR_OR: @@ -1776,10 +1792,34 @@ static ir_ref ir_promote_i2i(ir_ctx *ctx, ir_type type, ir_ref ref, ir_ref use) case IR_XOR: case IR_SHL: if (insn->op1 == insn->op2) { - insn->op2 = insn->op1 = ir_promote_i2i(ctx, type, insn->op1, ref); + insn->op2 = insn->op1 = ir_promote_i2i(ctx, type, insn->op1, ref, worklist); + } else { + insn->op1 = ir_promote_i2i(ctx, type, insn->op1, ref, worklist); + insn->op2 = ir_promote_i2i(ctx, type, insn->op2, ref, worklist); + } + insn->type = type; + return ref; +// case IR_DIV: +// case IR_MOD: +// case IR_SHR: +// case IR_SAR: +// case IR_FP2INT: +// TODO: ??? + case IR_COND: + if (insn->op2 == insn->op3) { + insn->op3 = insn->op2 = ir_promote_i2i(ctx, type, insn->op2, ref, worklist); } else { - insn->op1 = ir_promote_i2i(ctx, type, insn->op1, ref); - insn->op2 = ir_promote_i2i(ctx, type, insn->op2, ref); + insn->op2 = ir_promote_i2i(ctx, type, insn->op2, ref, worklist); + insn->op3 = ir_promote_i2i(ctx, type, insn->op3, ref, worklist); + } + insn->type = type; + return ref; + case IR_PHI: + for (p = insn->ops + 2, n = insn->inputs_count - 1; n > 0; p++, n--) { + input = *p; + if (input != ref) { + *p = ir_promote_i2i(ctx, type, input, ref, worklist); + } } insn->type = type; return ref; @@ -1854,58 +1894,163 @@ static ir_ref ir_ext_ref(ir_ctx *ctx, ir_ref var_ref, ir_ref src_ref, ir_op op, return ref; } -static bool ir_try_promote_ext(ir_ctx *ctx, ir_ref ext_ref, ir_insn *insn, ir_bitqueue *worklist) +static uint32_t _ir_estimated_control(ir_ctx *ctx, ir_ref val) { - ir_type type = insn->type; - ir_op op = insn->op; - ir_ref ref = insn->op1; - ir_insn *phi_insn = &ctx->ir_base[ref]; - ir_insn *op_insn; - ir_use_list *use_list; - ir_ref n, *p, use, op_ref; + ir_insn *insn; + ir_ref n, *p, input, result, ctrl; - /* Check for simple induction variable in the form: x2 = PHI(loop, x1, x3); x3 = ADD(x2, _); */ - if (phi_insn->op != IR_PHI - || phi_insn->inputs_count != 3 /* (2 values) */ - || ctx->ir_base[phi_insn->op1].op != IR_LOOP_BEGIN) { - return 0; + if (IR_IS_CONST_REF(val)) { + return 1; /* IR_START */ } - op_ref = phi_insn->op3; - op_insn = &ctx->ir_base[op_ref]; - if ((op_insn->op != IR_ADD && op_insn->op != IR_SUB && op_insn->op != IR_MUL) - || (op_insn->op1 != ref && op_insn->op2 != ref) - || ctx->use_lists[op_ref].count != 1) { - return 0; + insn = &ctx->ir_base[val]; + if (ir_op_flags[insn->op] & (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM)) { + return val; } - /* Check if we may change the type of the induction variable */ - use_list = &ctx->use_lists[ref]; - n = use_list->count; - for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) { - use = *p; - if (use == op_ref || use == ext_ref) { - continue; + IR_ASSERT(ir_op_flags[insn->op] & IR_OP_FLAG_DATA); + if (IR_OPND_KIND(ir_op_flags[insn->op], 1) == IR_OPND_CONTROL_DEP) { + return insn->op1; + } + + n = insn->inputs_count; + p = insn->ops + 1; + + result = 1; + for (; n > 0; p++, n--) { + input = *p; + ctrl = _ir_estimated_control(ctx, input); + if (ctrl > result) { // TODO: check dominance depth instead of order + result = ctrl; + } + } + return result; +} + +static bool ir_is_loop_invariant(ir_ctx *ctx, ir_ref ref, ir_ref loop) +{ + ref = _ir_estimated_control(ctx, ref); + return ref < loop; // TODO: check dominance instead of order +} + +static bool ir_is_cheaper_ext(ir_ctx *ctx, ir_ref ref, ir_ref loop, ir_ref ext_ref, ir_op op) +{ + if (IR_IS_CONST_REF(ref)) { + return 1; + } else { + ir_insn *insn = &ctx->ir_base[ref]; + + if (insn->op == IR_LOAD) { + if (ir_is_loop_invariant(ctx, ref, loop)) { + return 1; + } else { + /* ZEXT(LOAD(_, _)) costs the same as LOAD(_, _) */ + if (ctx->use_lists[ref].count == 2) { + return 1; + } else if (ctx->use_lists[ref].count == 3) { + ir_use_list *use_list = &ctx->use_lists[ref]; + ir_ref *p, n, use; + + for (p = &ctx->use_edges[use_list->refs], n = use_list->count; n > 0; p++, n--) { + use = *p; + if (use != ext_ref) { + ir_insn *use_insn = &ctx->ir_base[use]; + + if (use_insn->op != op + && (!(ir_op_flags[use_insn->op] & (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM)) + || use_insn->op1 != ref)) { + return 0; + } + } + } + return 1; + } + } + return 0; } else { - ir_insn *use_insn = &ctx->ir_base[use]; + return ir_is_loop_invariant(ctx, ref, loop); + } + } +} - if ((use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) - && (use_insn->op1 == ref || use_insn->op2 == ref)) { - continue; - } else if (use_insn->op == IR_IF) { +static bool ir_try_promote_induction_var_ext(ir_ctx *ctx, ir_ref ext_ref, ir_ref phi_ref, ir_ref op_ref, ir_bitqueue *worklist) +{ + ir_op op = ctx->ir_base[ext_ref].op; + ir_type type = ctx->ir_base[ext_ref].type; + ir_insn *phi_insn; + ir_use_list *use_list; + ir_ref n, *p, use, ext_ref_2 = IR_UNUSED; + + /* Check if we may change the type of the induction variable */ + use_list = &ctx->use_lists[phi_ref]; + n = use_list->count; + if (n > 1) { + for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) { + use = *p; + if (use == op_ref || use == ext_ref) { continue; } else { - return 0; + ir_insn *use_insn = &ctx->ir_base[use]; + + if (use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) { + if (use_insn->op1 == phi_ref) { + if (ir_is_cheaper_ext(ctx, use_insn->op2, ctx->ir_base[phi_ref].op1, ext_ref, op)) { + continue; + } + } else if (use_insn->op2 == phi_ref) { + if (ir_is_cheaper_ext(ctx, use_insn->op1, ctx->ir_base[phi_ref].op1, ext_ref, op)) { + continue; + } + } + return 0; + } else if (use_insn->op == IR_IF) { + continue; + } else if (!ext_ref_2 && use_insn->op == op && use_insn->type == type) { + ext_ref_2 = use; + continue; + } else { + return 0; + } } } } - phi_insn->type = insn->type; - op_insn->type = insn->type; + use_list = &ctx->use_lists[op_ref]; + n = use_list->count; + if (n > 1) { + for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) { + use = *p; + if (use == phi_ref || use == ext_ref) { + continue; + } else { + ir_insn *use_insn = &ctx->ir_base[use]; + + if (use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) { + if (use_insn->op1 == phi_ref) { + if (ir_is_cheaper_ext(ctx, use_insn->op2, ctx->ir_base[phi_ref].op1, ext_ref, op)) { + continue; + } + } else if (use_insn->op2 == phi_ref) { + if (ir_is_cheaper_ext(ctx, use_insn->op1, ctx->ir_base[phi_ref].op1, ext_ref, op)) { + continue; + } + } + return 0; + } else if (use_insn->op == IR_IF) { + continue; + } else if (!ext_ref_2 && use_insn->op == op && use_insn->type == type) { + ext_ref_2 = use; + continue; + } else { + return 0; + } + } + } + } - for (n = 0; n < ctx->use_lists[ref].count; n++) { + for (n = 0; n < ctx->use_lists[phi_ref].count; n++) { /* "use_lists" may be reallocated by ir_ext_ref() */ - use = ctx->use_edges[ctx->use_lists[ref].refs + n]; + use = ctx->use_edges[ctx->use_lists[phi_ref].refs + n]; if (use == ext_ref) { continue; } else { @@ -1913,11 +2058,14 @@ static bool ir_try_promote_ext(ir_ctx *ctx, ir_ref ext_ref, ir_insn *insn, ir_bi if (use_insn->op == IR_IF) { continue; + } else if (use_insn->op == op) { + IR_ASSERT(ext_ref_2 == use); + continue; } IR_ASSERT(((use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) || use_insn->op == IR_ADD || use_insn->op == IR_SUB || use_insn->op == IR_MUL) - && (use_insn->op1 == ref || use_insn->op2 == ref)); - if (use_insn->op1 != ref) { + && (use_insn->op1 == phi_ref || use_insn->op2 == phi_ref)); + if (use_insn->op1 != phi_ref) { if (IR_IS_CONST_REF(use_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op1].op)) { ctx->ir_base[use].op1 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op1], op, type); @@ -1926,7 +2074,7 @@ static bool ir_try_promote_ext(ir_ctx *ctx, ir_ref ext_ref, ir_insn *insn, ir_bi } ir_bitqueue_add(worklist, use); } - if (use_insn->op2 != ref) { + if (use_insn->op2 != phi_ref) { if (IR_IS_CONST_REF(use_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op2].op)) { ctx->ir_base[use].op2 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op2], op, type); @@ -1938,19 +2086,108 @@ static bool ir_try_promote_ext(ir_ctx *ctx, ir_ref ext_ref, ir_insn *insn, ir_bi } } - ir_iter_replace_insn(ctx, ext_ref, ref, worklist); + if (ctx->use_lists[op_ref].count > 1) { + for (n = 0; n < ctx->use_lists[op_ref].count; n++) { + /* "use_lists" may be reallocated by ir_ext_ref() */ + use = ctx->use_edges[ctx->use_lists[op_ref].refs + n]; + if (use == ext_ref || use == phi_ref) { + continue; + } else { + ir_insn *use_insn = &ctx->ir_base[use]; + + if (use_insn->op == IR_IF) { + continue; + } else if (use_insn->op == op) { + IR_ASSERT(ext_ref_2 == use); + continue; + } + IR_ASSERT(use_insn->op >= IR_EQ && use_insn->op <= IR_UGT); + if (use_insn->op1 != op_ref) { + if (IR_IS_CONST_REF(use_insn->op1) + && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op1].op)) { + ctx->ir_base[use].op1 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op1], op, type); + } else { + ctx->ir_base[use].op1 = ir_ext_ref(ctx, use, use_insn->op1, op, type, worklist); + } + ir_bitqueue_add(worklist, use); + } + if (use_insn->op2 != op_ref) { + if (IR_IS_CONST_REF(use_insn->op2) + && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op2].op)) { + ctx->ir_base[use].op2 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op2], op, type); + } else { + ctx->ir_base[use].op2 = ir_ext_ref(ctx, use, use_insn->op2, op, type, worklist); + } + ir_bitqueue_add(worklist, use); + } + } + } + } + + ir_iter_replace_insn(ctx, ext_ref, ctx->ir_base[ext_ref].op1, worklist); - phi_insn = &ctx->ir_base[ref]; + if (ext_ref_2) { + ir_iter_replace_insn(ctx, ext_ref_2, ctx->ir_base[ext_ref_2].op1, worklist); + } + + ctx->ir_base[op_ref].type = type; + + phi_insn = &ctx->ir_base[phi_ref]; + phi_insn->type = type; if (IR_IS_CONST_REF(phi_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[phi_insn->op2].op)) { - ctx->ir_base[ref].op2 = ir_ext_const(ctx, &ctx->ir_base[phi_insn->op2], op, type); + ctx->ir_base[phi_ref].op2 = ir_ext_const(ctx, &ctx->ir_base[phi_insn->op2], op, type); } else { - ctx->ir_base[ref].op2 = ir_ext_ref(ctx, ref, phi_insn->op2, op, type, worklist); + ctx->ir_base[phi_ref].op2 = ir_ext_ref(ctx, phi_ref, phi_insn->op2, op, type, worklist); } return 1; } +static bool ir_try_promote_ext(ir_ctx *ctx, ir_ref ext_ref, ir_insn *insn, ir_bitqueue *worklist) + { + ir_ref ref = insn->op1; + + /* Check for simple induction variable in the form: x2 = PHI(loop, x1, x3); x3 = ADD(x2, _); */ + insn = &ctx->ir_base[ref]; + if (insn->op == IR_PHI + && insn->inputs_count == 3 /* (2 values) */ + && ctx->ir_base[insn->op1].op == IR_LOOP_BEGIN) { + ir_ref op_ref = insn->op3; + ir_insn *op_insn = &ctx->ir_base[op_ref]; + + if (op_insn->op == IR_ADD || op_insn->op == IR_SUB || op_insn->op == IR_MUL) { + if (op_insn->op1 == ref) { + if (ir_is_loop_invariant(ctx, op_insn->op2, insn->op1)) { + return ir_try_promote_induction_var_ext(ctx, ext_ref, ref, op_ref, worklist); + } + } else if (op_insn->op2 == ref) { + if (ir_is_loop_invariant(ctx, op_insn->op1, insn->op1)) { + return ir_try_promote_induction_var_ext(ctx, ext_ref, ref, op_ref, worklist); + } + } + } + } else if (insn->op == IR_ADD || insn->op == IR_SUB || insn->op == IR_MUL) { + if (!IR_IS_CONST_REF(insn->op1) + && ctx->ir_base[insn->op1].op == IR_PHI + && ctx->ir_base[insn->op1].inputs_count == 3 /* (2 values) */ + && ctx->ir_base[insn->op1].op3 == ref + && ctx->ir_base[ctx->ir_base[insn->op1].op1].op == IR_LOOP_BEGIN + && ir_is_loop_invariant(ctx, insn->op2, ctx->ir_base[insn->op1].op1)) { + return ir_try_promote_induction_var_ext(ctx, ext_ref, insn->op1, ref, worklist); + } else if (!IR_IS_CONST_REF(insn->op2) + && ctx->ir_base[insn->op2].op == IR_PHI + && ctx->ir_base[insn->op2].inputs_count == 3 /* (2 values) */ + && ctx->ir_base[insn->op2].op3 == ref + && ctx->ir_base[ctx->ir_base[insn->op2].op1].op == IR_LOOP_BEGIN + && ir_is_loop_invariant(ctx, insn->op1, ctx->ir_base[insn->op2].op1)) { + return ir_try_promote_induction_var_ext(ctx, ext_ref, insn->op2, ref, worklist); + } + } + + return 0; +} + static void ir_get_true_false_refs(const ir_ctx *ctx, ir_ref if_ref, ir_ref *if_true_ref, ir_ref *if_false_ref) { ir_use_list *use_list = &ctx->use_lists[if_ref]; @@ -1969,11 +2206,47 @@ static void ir_get_true_false_refs(const ir_ctx *ctx, ir_ref if_ref, ir_ref *if_ } } -static void ir_merge_blocks(ir_ctx *ctx, ir_ref end, ir_ref begin, ir_bitqueue *worklist2) +static void ir_merge_blocks(ir_ctx *ctx, ir_ref end, ir_ref begin, ir_bitqueue *worklist) { ir_ref prev, next; ir_use_list *use_list; + if (ctx->use_lists[begin].count > 1) { + ir_ref *p, n, i, use; + ir_insn *use_insn; + ir_ref region = end; + ir_ref next = IR_UNUSED; + + while (!IR_IS_BB_START(ctx->ir_base[region].op)) { + region = ctx->ir_base[region].op1; + } + + use_list = &ctx->use_lists[begin]; + n = use_list->count; + for (p = &ctx->use_edges[use_list->refs], i = 0; i < n; p++, i++) { + use = *p; + use_insn = &ctx->ir_base[use]; + if (ir_op_flags[use_insn->op] & IR_OP_FLAG_CONTROL) { + IR_ASSERT(!next); + next = use; + } else { + IR_ASSERT(use_insn->op == IR_VAR); + IR_ASSERT(use_insn->op1 == begin); + use_insn->op1 = region; + if (ir_use_list_add(ctx, region, use)) { + /* restore after reallocation */ + use_list = &ctx->use_lists[begin]; + n = use_list->count; + p = &ctx->use_edges[use_list->refs + i]; + } + } + } + + IR_ASSERT(next); + ctx->use_edges[use_list->refs] = next; + use_list->count = 1; + } + IR_ASSERT(ctx->ir_base[begin].op == IR_BEGIN); IR_ASSERT(ctx->ir_base[end].op == IR_END); IR_ASSERT(ctx->ir_base[begin].op1 == end); @@ -1994,7 +2267,7 @@ static void ir_merge_blocks(ir_ctx *ctx, ir_ref end, ir_ref begin, ir_bitqueue * ir_use_list_replace_one(ctx, prev, end, next); if (ctx->ir_base[prev].op == IR_BEGIN || ctx->ir_base[prev].op == IR_MERGE) { - ir_bitqueue_add(worklist2, prev); + ir_bitqueue_add(worklist, prev); } } @@ -2950,6 +3223,68 @@ static void ir_iter_optimize_merge(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge } } +static ir_ref ir_find_ext_use(ir_ctx *ctx, ir_ref ref) +{ + ir_use_list *use_list = &ctx->use_lists[ref]; + ir_ref *p, n, use; + ir_insn *use_insn; + + for (p = &ctx->use_edges[use_list->refs], n = use_list->count; n > 0; p++, n--) { + use = *p; + use_insn = &ctx->ir_base[use]; + if (use_insn->op == IR_SEXT || use_insn->op == IR_ZEXT) { + return use; + } + } + return IR_UNUSED; +} + +static void ir_iter_optimize_induction_var(ir_ctx *ctx, ir_ref phi_ref, ir_ref op_ref, ir_bitqueue *worklist) +{ + ir_ref ext_ref; + + ext_ref = ir_find_ext_use(ctx, phi_ref); + if (!ext_ref) { + ext_ref = ir_find_ext_use(ctx, op_ref); + } + if (ext_ref) { + ir_try_promote_induction_var_ext(ctx, ext_ref, phi_ref, op_ref, worklist); + } +} + +static void ir_iter_optimize_loop(ir_ctx *ctx, ir_ref loop_ref, ir_insn *loop, ir_bitqueue *worklist) +{ + ir_ref n; + + if (loop->inputs_count != 2 || ctx->use_lists[loop_ref].count <= 1) { + return; + } + + /* Check for simple induction variable in the form: x2 = PHI(loop, x1, x3); x3 = ADD(x2, _); */ + for (n = 0; n < ctx->use_lists[loop_ref].count; n++) { + /* "use_lists" may be reallocated by ir_ext_ref() */ + ir_ref use = ctx->use_edges[ctx->use_lists[loop_ref].refs + n]; + ir_insn *use_insn = &ctx->ir_base[use]; + + if (use_insn->op == IR_PHI) { + ir_ref op_ref = use_insn->op3; + ir_insn *op_insn = &ctx->ir_base[op_ref]; + + if (op_insn->op == IR_ADD || op_insn->op == IR_SUB || op_insn->op == IR_MUL) { + if (op_insn->op1 == use) { + if (ir_is_loop_invariant(ctx, op_insn->op2, loop_ref)) { + ir_iter_optimize_induction_var(ctx, use, op_ref, worklist); + } + } else if (op_insn->op2 == use) { + if (ir_is_loop_invariant(ctx, op_insn->op1, loop_ref)) { + ir_iter_optimize_induction_var(ctx, use, op_ref, worklist); + } + } + } + } + } +} + static ir_ref ir_iter_optimize_condition(ir_ctx *ctx, ir_ref control, ir_ref condition, bool *swap) { ir_insn *condition_insn = &ctx->ir_base[condition]; @@ -2996,6 +3331,10 @@ static ir_ref ir_iter_optimize_condition(ir_ctx *ctx, ir_ref control, ir_ref con condition_insn = &ctx->ir_base[condition]; } + if (condition_insn->op == IR_ALLOCA || condition_insn->op == IR_VADDR) { + return IR_TRUE; + } + if (!IR_IS_CONST_REF(condition) && ctx->use_lists[condition].count > 1) { condition = ir_check_dominating_predicates(ctx, control, condition); } @@ -3042,6 +3381,7 @@ static void ir_iter_optimize_if(ir_ctx *ctx, ir_ref ref, ir_insn *insn, ir_bitqu insn->optx = IR_OPTX(IR_END, IR_VOID, 1); if (!IR_IS_CONST_REF(insn->op2)) { ir_use_list_remove_one(ctx, insn->op2, ref); + ir_bitqueue_add(worklist, insn->op2); } insn->op2 = IR_UNUSED; @@ -3142,14 +3482,14 @@ void ir_iter_opt(ir_ctx *ctx, ir_bitqueue *worklist) case IR_FP2FP: if (insn->type == IR_FLOAT) { if (ir_may_promote_d2f(ctx, insn->op1)) { - ir_ref ref = ir_promote_d2f(ctx, insn->op1, i); + ir_ref ref = ir_promote_d2f(ctx, insn->op1, i, worklist); insn->op1 = ref; ir_iter_replace_insn(ctx, i, ref, worklist); break; } } else { if (ir_may_promote_f2d(ctx, insn->op1)) { - ir_ref ref = ir_promote_f2d(ctx, insn->op1, i); + ir_ref ref = ir_promote_f2d(ctx, insn->op1, i, worklist); insn->op1 = ref; ir_iter_replace_insn(ctx, i, ref, worklist); break; @@ -3159,17 +3499,17 @@ void ir_iter_opt(ir_ctx *ctx, ir_bitqueue *worklist) case IR_FP2INT: if (ctx->ir_base[insn->op1].type == IR_DOUBLE) { if (ir_may_promote_d2f(ctx, insn->op1)) { - insn->op1 = ir_promote_d2f(ctx, insn->op1, i); + insn->op1 = ir_promote_d2f(ctx, insn->op1, i, worklist); } } else { if (ir_may_promote_f2d(ctx, insn->op1)) { - insn->op1 = ir_promote_f2d(ctx, insn->op1, i); + insn->op1 = ir_promote_f2d(ctx, insn->op1, i, worklist); } } goto folding; case IR_TRUNC: - if (ir_may_promote_i2i(ctx, insn->type, insn->op1)) { - ir_ref ref = ir_promote_i2i(ctx, insn->type, insn->op1, i); + if (ir_may_promote_trunc(ctx, insn->type, insn->op1)) { + ir_ref ref = ir_promote_i2i(ctx, insn->type, insn->op1, i, worklist); insn->op1 = ref; ir_iter_replace_insn(ctx, i, ref, worklist); break; @@ -3193,12 +3533,13 @@ void ir_iter_opt(ir_ctx *ctx, ir_bitqueue *worklist) if (!(ctx->flags & IR_OPT_CFG)) { /* pass */ } else if (insn->op == IR_BEGIN) { - if (ctx->ir_base[insn->op1].op == IR_END - && ctx->use_lists[i].count == 1) { + if (insn->op1 && ctx->ir_base[insn->op1].op == IR_END) { ir_merge_blocks(ctx, insn->op1, i, worklist); } } else if (insn->op == IR_MERGE) { ir_iter_optimize_merge(ctx, i, insn, worklist); + } else if (insn->op == IR_LOOP_BEGIN) { + ir_iter_optimize_loop(ctx, i, insn, worklist); } } else if (ir_is_dead_load(ctx, i)) { ir_ref next; diff --git a/ext/opcache/jit/ir/ir_x86.dasc b/ext/opcache/jit/ir/ir_x86.dasc index 3b6cf156ad909..d01a8c41359aa 100644 --- a/ext/opcache/jit/ir/ir_x86.dasc +++ b/ext/opcache/jit/ir/ir_x86.dasc @@ -650,6 +650,26 @@ IR_ALWAYS_INLINE ir_mem IR_MEM(ir_reg base, int32_t offset, ir_reg index, int32_ || } |.endmacro +/* Like ASM_REG_IMM_OP, but op1 accepts r16,r32,r64 (not r8) */ +|.macro ASM_REG16_IMM_OP, op, type, op1, op2 +|| switch (ir_type_size[type]) { +|| default: +|| IR_ASSERT(0); +|| case 1: +|| case 2: +| op Rw(op1), (op2 & 0xffff) +|| break; +|| case 4: +| op Rd(op1), op2 +|| break; +|.if X64 +|| case 8: +| op Rq(op1), op2 +|| break; +|.endif +|| } +|.endmacro + |.macro ASM_MEM_REG_OP, op, type, op1, op2 | ASM_EXPAND_OP1_MEM ASM_EXPAND_TYPE_MEM_REG, op, type, op1, op2 |.endmacro @@ -1003,6 +1023,8 @@ const char *ir_reg_name(int8_t reg, ir_type type) _(LEA_SI_B) \ _(LEA_B_SI_O) \ _(LEA_SI_B_O) \ + _(LEA_SYM_O) \ + _(LEA_O_SYM) \ _(INC) \ _(DEC) \ _(MUL_PWR2) \ @@ -1064,6 +1086,10 @@ const char *ir_reg_name(int8_t reg, ir_type type) _(SSE_CEIL) \ _(SSE_TRUNC) \ _(SSE_NEARBYINT) \ + _(BIT_OP) \ + +#define IR_LEA_FIRST IR_LEA_OB +#define IR_LEA_LAST IR_LEA_O_SYM #define IR_RULE_ENUM(name) IR_ ## name, @@ -1395,6 +1421,7 @@ op2_const: case IR_DIV_PWR2: case IR_OP_INT: case IR_OP_FP: + case IR_BIT_OP: flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG; break; case IR_MOD_PWR2: @@ -1584,7 +1611,7 @@ static void ir_match_fuse_addr(ir_ctx *ctx, ir_ref addr_ref) if (!rule) { ctx->rules[addr_ref] = rule = ir_match_insn(ctx, addr_ref); } - if (rule >= IR_LEA_OB && rule <= IR_LEA_SI_B_O) { + if (rule >= IR_LEA_FIRST && rule <= IR_LEA_LAST) { ir_use_list *use_list; ir_ref j; @@ -1972,6 +1999,19 @@ static uint32_t ir_match_insn(ir_ctx *ctx, ir_ref ref) if ((ctx->flags & IR_OPT_CODEGEN) && IR_IS_CONST_REF(insn->op2)) { op2_insn = &ctx->ir_base[insn->op2]; if (IR_IS_CONST_REF(insn->op1)) { + ir_insn *op1_insn = &ctx->ir_base[insn->op1]; + + if (insn->op == IR_ADD + && IR_IS_SYM_CONST(op1_insn->op) + && !IR_IS_SYM_CONST(op2_insn->op) + && IR_IS_SIGNED_32BIT((intptr_t)ir_sym_val(ctx, op1_insn) + (intptr_t)op2_insn->val.i64)) { + return IR_LEA_SYM_O; + } else if (insn->op == IR_ADD + && IR_IS_SYM_CONST(op2_insn->op) + && !IR_IS_SYM_CONST(op1_insn->op) + && IR_IS_SIGNED_32BIT((intptr_t)ir_sym_val(ctx, op2_insn) + (intptr_t)op1_insn->val.i64)) { + return IR_LEA_O_SYM; + } // const // TODO: add support for sym+offset ??? } else if (IR_IS_SYM_CONST(op2_insn->op)) { @@ -2262,6 +2302,9 @@ binop_fp: // return IR_COPY_INT; } else if (op2_insn->val.i64 == -1) { // -1 + } else if (IR_IS_POWER_OF_TWO(op2_insn->val.u64) && !IR_IS_SIGNED_32BIT(op2_insn->val.i64)) { + /* OR(X, PWR2) => BTS */ + return IR_BIT_OP; } } goto binop_int; @@ -2276,6 +2319,9 @@ binop_fp: // 0 } else if (op2_insn->val.i64 == -1) { // return IR_COPY_INT; + } else if (IR_IS_POWER_OF_TWO(~op2_insn->val.u64) && !IR_IS_SIGNED_32BIT(op2_insn->val.i64)) { + /* AND(X, ~PWR2) => BTR */ + return IR_BIT_OP; } } goto binop_int; @@ -3264,7 +3310,11 @@ static void ir_emit_mov_ext(ir_ctx *ctx, ir_type type, ir_reg dst, ir_reg src) | ASM_REG_REG_OP mov, type, dst, src } else if (ir_type_size[type] == 2) { if (IR_IS_TYPE_SIGNED(type)) { - | movsx Rd(dst), Rw(src) + if (dst == IR_REG_RAX && src == IR_REG_RAX) { + | cwde + } else { + | movsx Rd(dst), Rw(src) + } } else { | movzx Rd(dst), Rw(src) } @@ -3311,8 +3361,8 @@ static ir_mem ir_fuse_addr(ir_ctx *ctx, ir_ref root, ir_ref ref) ir_reg base_reg = IR_REG_NONE, index_reg; int32_t offset = 0, scale; - IR_ASSERT(((rule & IR_RULE_MASK) >= IR_LEA_OB && - (rule & IR_RULE_MASK) <= IR_LEA_SI_B_O) || + IR_ASSERT(((rule & IR_RULE_MASK) >= IR_LEA_FIRST && + (rule & IR_RULE_MASK) <= IR_LEA_LAST) || rule == IR_STATIC_ALLOCA); switch (rule & IR_RULE_MASK) { default: @@ -3498,6 +3548,22 @@ static ir_mem ir_fuse_addr(ir_ctx *ctx, ir_ref root, ir_ref ref) op1_insn = &ctx->ir_base[op1_insn->op1]; scale = ctx->ir_base[op1_insn->op2].val.i32; break; + case IR_LEA_SYM_O: + op1_insn = &ctx->ir_base[insn->op1]; + op2_insn = &ctx->ir_base[insn->op2]; + offset = (intptr_t)ir_sym_val(ctx, op1_insn) + (intptr_t)op2_insn->val.i64; + base_reg_ref = index_reg_ref = IR_UNUSED; + scale = 1; + offset_insn = NULL; + break; + case IR_LEA_O_SYM: + op1_insn = &ctx->ir_base[insn->op1]; + op2_insn = &ctx->ir_base[insn->op2]; + offset = (intptr_t)ir_sym_val(ctx, op2_insn) + (intptr_t)op1_insn->val.i64; + base_reg_ref = index_reg_ref = IR_UNUSED; + scale = 1; + offset_insn = NULL; + break; case IR_ALLOCA: offset = IR_SPILL_POS_TO_OFFSET(insn->op3); base_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; @@ -4303,6 +4369,45 @@ static void ir_emit_mul_div_mod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn) } } +static void ir_emit_bit_op(ir_ctx *ctx, ir_ref def, ir_insn *insn) +{ + ir_backend_data *data = ctx->data; + dasm_State **Dst = &data->dasm_state; + ir_type type = insn->type; + ir_ref op1 = insn->op1; + ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); + ir_reg op1_reg = ctx->regs[def][1]; + + IR_ASSERT(IR_IS_CONST_REF(insn->op2)); + IR_ASSERT(!IR_IS_SYM_CONST(ctx->ir_base[insn->op2].op)); + IR_ASSERT(def_reg != IR_REG_NONE); + + if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) { + op1_reg = IR_REG_NUM(op1_reg); + ir_emit_load(ctx, type, op1_reg, op1); + } + if (def_reg != op1_reg) { + if (op1_reg != IR_REG_NONE) { + ir_emit_mov(ctx, type, def_reg, op1_reg); + } else { + ir_emit_load(ctx, type, def_reg, op1); + } + } + if (insn->op == IR_OR) { + uint32_t bit = IR_LOG2(ctx->ir_base[insn->op2].val.u64); + + | ASM_REG16_IMM_OP, bts, type, def_reg, bit + } else { + IR_ASSERT(insn->op == IR_AND); + uint32_t bit = IR_LOG2(~ctx->ir_base[insn->op2].val.u64); + + | ASM_REG16_IMM_OP, btr, type, def_reg, bit + } + if (IR_REG_SPILLED(ctx->regs[def][0])) { + ir_emit_store(ctx, type, def, def_reg); + } +} + static void ir_emit_sdiv_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn) { ir_backend_data *data = ctx->data; @@ -5186,7 +5291,7 @@ static void ir_emit_mul_div_mod(ir_ctx *ctx, ir_ref def, ir_insn *insn) } else if (ir_type_size[type] == 2) { | cwd } else { - | movsx ax, al + | cbw } if (op2_reg != IR_REG_NONE) { | ASM_REG_OP idiv, type, op2_reg @@ -6813,7 +6918,11 @@ static void ir_emit_sext(ir_ctx *ctx, ir_ref def, ir_insn *insn) } if (ir_type_size[src_type] == 1) { if (ir_type_size[dst_type] == 2) { - | movsx Rw(def_reg), Rb(op1_reg) + if (def_reg == IR_REG_RAX && op1_reg == IR_REG_RAX) { + | cbw + } else { + | movsx Rw(def_reg), Rb(op1_reg) + } } else if (ir_type_size[dst_type] == 4) { | movsx Rd(def_reg), Rb(op1_reg) } else { @@ -6825,7 +6934,11 @@ static void ir_emit_sext(ir_ctx *ctx, ir_ref def, ir_insn *insn) } } else if (ir_type_size[src_type] == 2) { if (ir_type_size[dst_type] == 4) { - | movsx Rd(def_reg), Rw(op1_reg) + if (def_reg == IR_REG_RAX && op1_reg == IR_REG_RAX) { + | cwde + } else { + | movsx Rd(def_reg), Rw(op1_reg) + } } else { IR_ASSERT(ir_type_size[dst_type] == 8); IR_ASSERT(sizeof(void*) == 8); @@ -6838,7 +6951,11 @@ static void ir_emit_sext(ir_ctx *ctx, ir_ref def, ir_insn *insn) IR_ASSERT(ir_type_size[dst_type] == 8); IR_ASSERT(sizeof(void*) == 8); |.if X64 - | movsxd Rq(def_reg), Rd(op1_reg) + if (def_reg == IR_REG_RAX && op1_reg == IR_REG_RAX) { + | cdqe + } else { + | movsxd Rq(def_reg), Rd(op1_reg) + } |.endif } } else if (IR_IS_CONST_REF(insn->op1)) { @@ -7203,6 +7320,8 @@ static void ir_emit_int2fp(ir_ctx *ctx, ir_ref def, ir_insn *insn) |.else || if (ir_type_size[src_type] == 1) { | movsx Rd(op1_reg), Rb(op1_reg) +|| } else if (op1_reg == IR_REG_RAX) { + | cwde || } else { | movsx Rd(op1_reg), Rw(op1_reg) || } @@ -8502,7 +8621,11 @@ static void ir_emit_switch(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn) case 4: |.if X64 if (IR_IS_TYPE_SIGNED(type)) { - | movsxd Ra(op2_reg), Rd(op2_reg) + if (op2_reg == IR_REG_RAX) { + | cdqe + } else { + | movsxd Ra(op2_reg), Rd(op2_reg) + } } else { | mov Rd(op2_reg), Rd(op2_reg) } @@ -10603,6 +10726,8 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) case IR_LEA_SI_B: case IR_LEA_B_SI_O: case IR_LEA_SI_B_O: + case IR_LEA_SYM_O: + case IR_LEA_O_SYM: ir_emit_lea(ctx, i, insn->type); break; case IR_MUL_PWR2: @@ -10610,6 +10735,9 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) case IR_MOD_PWR2: ir_emit_mul_div_mod_pwr2(ctx, i, insn); break; + case IR_BIT_OP: + ir_emit_bit_op(ctx, i, insn); + break; case IR_SDIV_PWR2: ir_emit_sdiv_pwr2(ctx, i, insn); break; diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 7a423ce6a6529..355178d9d51ed 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -98,7 +98,7 @@ static const void *zend_jit_func_trace_counter_handler = NULL; static const void *zend_jit_ret_trace_counter_handler = NULL; static const void *zend_jit_loop_trace_counter_handler = NULL; -static int ZEND_FASTCALL zend_runtime_jit(void); +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_runtime_jit(ZEND_OPCODE_HANDLER_ARGS); static int zend_jit_trace_op_len(const zend_op *opline); static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op *opline); @@ -2871,7 +2871,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op if (GCC_GLOBAL_REGS) { ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit))); } else { - ir_RETURN(ir_CONST_I32(1)); /* ZEND_VM_ENTER */ + zend_jit_vm_enter(jit, jit_IP(jit)); } ir_IF_TRUE(if_hook_enter); } @@ -3074,11 +3074,18 @@ static int zend_real_jit_func(zend_op_array *op_array, zend_script *script, cons } /* Run-time JIT handler */ -static int ZEND_FASTCALL zend_runtime_jit(void) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_runtime_jit(ZEND_OPCODE_HANDLER_ARGS) { - zend_execute_data *execute_data = EG(current_execute_data); +#if GCC_GLOBAL_REGS + zend_execute_data *execute_data; + zend_op *opline; +#else + const zend_op *orig_opline = opline; +#endif + + execute_data = EG(current_execute_data); zend_op_array *op_array = &EX(func)->op_array; - zend_op *opline = op_array->opcodes; + opline = op_array->opcodes; zend_jit_op_array_extension *jit_extension; bool do_bailout = 0; @@ -3097,7 +3104,7 @@ static int ZEND_FASTCALL zend_runtime_jit(void) } } jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array); - opline->handler = jit_extension->orig_handler; + ((zend_op*)opline)->handler = jit_extension->orig_handler; /* perform real JIT for this function */ zend_real_jit_func(op_array, NULL, NULL, ZEND_JIT_ON_FIRST_EXEC); @@ -3116,7 +3123,11 @@ static int ZEND_FASTCALL zend_runtime_jit(void) } /* JIT-ed code is going to be called by VM */ - return 0; +#if GCC_GLOBAL_REGS + return; // ZEND_VM_CONTINUE +#else + return orig_opline; // ZEND_VM_CONTINUE +#endif } void zend_jit_check_funcs(HashTable *function_table, bool is_method) { @@ -3171,6 +3182,8 @@ void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend op_array->opcodes[i].handler = jit_extension->orig_handlers[i]; } + EX(opline) = opline; + /* perform real JIT for this function */ zend_real_jit_func(op_array, NULL, opline, ZEND_JIT_ON_HOT_COUNTERS); } zend_catch { diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 8fd7d94317b5d..b20afffa47df0 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1718,7 +1718,7 @@ static void ZEND_FASTCALL zend_jit_fast_assign_concat_helper(zval *op1, zval *op zend_string *result_str; uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(Z_STR_P(op1), Z_STR_P(op2)); - if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) { + if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) { zend_throw_error(NULL, "String size overflow"); return; } @@ -1754,7 +1754,7 @@ static void ZEND_FASTCALL zend_jit_fast_concat_helper(zval *result, zval *op1, z zend_string *result_str; uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(Z_STR_P(op1), Z_STR_P(op2)); - if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) { + if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) { zend_throw_error(NULL, "String size overflow"); return; } @@ -1778,7 +1778,7 @@ static void ZEND_FASTCALL zend_jit_fast_concat_tmp_helper(zval *result, zval *op zend_string *result_str; uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(Z_STR_P(op1), Z_STR_P(op2)); - if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) { + if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) { zend_throw_error(NULL, "String size overflow"); return; } @@ -1900,9 +1900,8 @@ static bool ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_arg_info *arg { zend_execute_data *execute_data = EG(current_execute_data); const zend_op *opline = EX(opline); - void **cache_slot = CACHE_ADDR(opline->extended_value); bool ret = zend_check_user_type_slow( - &arg_info->type, arg, /* ref */ NULL, cache_slot, /* is_return_type */ false); + &arg_info->type, arg, /* ref */ NULL, /* is_return_type */ false); if (UNEXPECTED(!ret)) { zend_verify_arg_error(EX(func), arg_info, opline->op1.num, arg); return 0; @@ -1910,7 +1909,7 @@ static bool ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_arg_info *arg return ret; } -static void ZEND_FASTCALL zend_jit_verify_return_slow(zval *arg, const zend_op_array *op_array, zend_arg_info *arg_info, void **cache_slot) +static void ZEND_FASTCALL zend_jit_verify_return_slow(zval *arg, const zend_op_array *op_array, zend_arg_info *arg_info) { if (Z_TYPE_P(arg) == IS_NULL) { ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type)); @@ -1919,7 +1918,7 @@ static void ZEND_FASTCALL zend_jit_verify_return_slow(zval *arg, const zend_op_a } } if (UNEXPECTED(!zend_check_user_type_slow( - &arg_info->type, arg, /* ref */ NULL, cache_slot, /* is_return_type */ true))) { + &arg_info->type, arg, /* ref */ NULL, /* is_return_type */ true))) { zend_verify_return_error((zend_function*)op_array, arg); } } diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index e769c6caefb98..3ec8ae6041a53 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -21,6 +21,12 @@ #ifndef ZEND_JIT_INTERNAL_H #define ZEND_JIT_INTERNAL_H +#include "Zend/zend_types.h" +#include "Zend/zend_compile.h" +#include "Zend/zend_constants.h" +#include "Zend/Optimizer/zend_func_info.h" +#include "Zend/Optimizer/zend_call_graph.h" + /* Address Encoding */ typedef uintptr_t zend_jit_addr; @@ -183,17 +189,18 @@ extern const zend_op *zend_jit_halt_op; # define ZEND_OPCODE_HANDLER_RET void # define ZEND_OPCODE_HANDLER_ARGS EXECUTE_DATA_D # define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU -# define ZEND_OPCODE_HANDLER_ARGS_DC -# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC +# define ZEND_OPCODE_HANDLER_ARGS_EX +# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX # define ZEND_OPCODE_RETURN() return # define ZEND_OPCODE_TAIL_CALL(handler) do { \ handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); \ return; \ } while(0) # define ZEND_OPCODE_TAIL_CALL_EX(handler, arg) do { \ - handler(arg ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC); \ + handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX arg); \ return; \ } while(0) +# define ZEND_VM_ENTER_BIT 0 #else # define EXECUTE_DATA_D zend_execute_data* execute_data # define EXECUTE_DATA_C execute_data @@ -203,36 +210,39 @@ extern const zend_op *zend_jit_halt_op; # define OPLINE_C opline # define OPLINE_DC , OPLINE_D # define OPLINE_CC , OPLINE_C -# define ZEND_OPCODE_HANDLER_RET int -# define ZEND_OPCODE_HANDLER_ARGS EXECUTE_DATA_D -# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU EXECUTE_DATA_C -# define ZEND_OPCODE_HANDLER_ARGS_DC EXECUTE_DATA_DC -# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC EXECUTE_DATA_CC -# define ZEND_OPCODE_RETURN() return 0 +# define ZEND_OPCODE_HANDLER_RET const zend_op * +# define ZEND_OPCODE_HANDLER_ARGS EXECUTE_DATA_D OPLINE_DC +# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU EXECUTE_DATA_C OPLINE_CC +# define ZEND_OPCODE_HANDLER_ARGS_EX EXECUTE_DATA_D OPLINE_DC, +# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX EXECUTE_DATA_C OPLINE_CC, +# define ZEND_OPCODE_RETURN() return opline # define ZEND_OPCODE_TAIL_CALL(handler) do { \ return handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); \ } while(0) # define ZEND_OPCODE_TAIL_CALL_EX(handler, arg) do { \ - return handler(arg ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC); \ + return handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX arg); \ } while(0) +# define ZEND_VM_ENTER_BIT 1ULL #endif /* VM handlers */ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *zend_vm_opcode_handler_t)(ZEND_OPCODE_HANDLER_ARGS); /* VM helpers */ -ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(uint32_t call_info EXECUTE_DATA_DC); -ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_top_func_helper(uint32_t call_info EXECUTE_DATA_DC); -ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_func_helper(EXECUTE_DATA_D); +ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(ZEND_OPCODE_HANDLER_ARGS_EX uint32_t call_info); +ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_top_func_helper(ZEND_OPCODE_HANDLER_ARGS_EX uint32_t call_info); +ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_func_helper(ZEND_OPCODE_HANDLER_ARGS); ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_profile_helper(ZEND_OPCODE_HANDLER_ARGS); ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_counter_helper(ZEND_OPCODE_HANDLER_ARGS); ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_HANDLER_ARGS); -void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D); -void ZEND_FASTCALL zend_jit_copy_extra_args_helper_no_skip_recv(EXECUTE_DATA_D); +ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_copy_extra_args_helper(ZEND_OPCODE_HANDLER_ARGS); +ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_copy_extra_args_helper_no_skip_recv(ZEND_OPCODE_HANDLER_ARGS); bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D); +bool ZEND_FASTCALL zend_jit_nodiscard_helper(OPLINE_D); +bool ZEND_FASTCALL zend_jit_deprecated_nodiscard_helper(OPLINE_D); void ZEND_FASTCALL zend_jit_undefined_long_key(EXECUTE_DATA_D); void ZEND_FASTCALL zend_jit_undefined_long_key_ex(zend_long key EXECUTE_DATA_DC); void ZEND_FASTCALL zend_jit_undefined_string_key(EXECUTE_DATA_D); diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 968594b5fbb3c..60fcdff8a61f3 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -911,18 +911,9 @@ static ir_ref jit_IP32(zend_jit_ctx *jit) return ir_RLOAD_U32(ZREG_IP); } -static void jit_LOAD_IP(zend_jit_ctx *jit, ir_ref ref) -{ - if (GCC_GLOBAL_REGS) { - jit_STORE_IP(jit, ref); - } else { - ir_STORE(jit_EX(opline), ref); - } -} - static void jit_LOAD_IP_ADDR(zend_jit_ctx *jit, const zend_op *target) { - jit_LOAD_IP(jit, ir_CONST_ADDR(target)); + jit_STORE_IP(jit, ir_CONST_ADDR(target)); } static void zend_jit_track_last_valid_opline(zend_jit_ctx *jit) @@ -1008,7 +999,6 @@ static int zend_jit_save_call_chain(zend_jit_ctx *jit, uint32_t call_level) static int zend_jit_set_ip(zend_jit_ctx *jit, const zend_op *target) { ir_ref ref; - ir_ref addr = IR_UNUSED; if (jit->delayed_call_level) { if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) { @@ -1019,58 +1009,30 @@ static int zend_jit_set_ip(zend_jit_ctx *jit, const zend_op *target) if (jit->last_valid_opline) { zend_jit_use_last_valid_opline(jit); if (jit->last_valid_opline != target) { - if (GCC_GLOBAL_REGS) { - ref = jit_IP(jit); - } else { - addr = jit_EX(opline); - ref = ir_LOAD_A(addr); - } + ref = jit_IP(jit); if (target > jit->last_valid_opline) { ref = ir_ADD_OFFSET(ref, (uintptr_t)target - (uintptr_t)jit->last_valid_opline); } else { ref = ir_SUB_A(ref, ir_CONST_ADDR((uintptr_t)jit->last_valid_opline - (uintptr_t)target)); } - if (GCC_GLOBAL_REGS) { - jit_STORE_IP(jit, ref); - } else { - ir_STORE(addr, ref); - } + jit_STORE_IP(jit, ref); } } else { - if (GCC_GLOBAL_REGS) { - jit_STORE_IP(jit, ir_CONST_ADDR(target)); - } else { - ir_STORE(jit_EX(opline), ir_CONST_ADDR(target)); - } + jit_STORE_IP(jit, ir_CONST_ADDR(target)); } jit->reuse_ip = 0; zend_jit_set_last_valid_opline(jit, target); return 1; } -static int zend_jit_set_ip_ex(zend_jit_ctx *jit, const zend_op *target, bool set_ip_reg) -{ - if (!GCC_GLOBAL_REGS && set_ip_reg && !jit->last_valid_opline) { - /* Optimization to avoid duplicate constant load */ - ir_STORE(jit_EX(opline), ir_HARD_COPY_A(ir_CONST_ADDR(target))); - return 1; - } - return zend_jit_set_ip(jit, target); -} - static void jit_SET_EX_OPLINE(zend_jit_ctx *jit, const zend_op *target) { if (jit->last_valid_opline == target) { zend_jit_use_last_valid_opline(jit); - if (GCC_GLOBAL_REGS) { - // EX(opline) = opline - ir_STORE(jit_EX(opline), jit_IP(jit)); - } + // EX(opline) = opline + ir_STORE(jit_EX(opline), jit_IP(jit)); } else { ir_STORE(jit_EX(opline), ir_CONST_ADDR(target)); - if (!GCC_GLOBAL_REGS) { - zend_jit_reset_last_valid_opline(jit); - } } } @@ -1912,6 +1874,18 @@ static void zend_jit_check_timeout(zend_jit_ctx *jit, const zend_op *opline, con } } +static void zend_jit_vm_enter(zend_jit_ctx *jit, ir_ref to_opline) +{ + // ZEND_VM_ENTER() + ir_RETURN(ir_OR_A(to_opline, ir_CONST_ADDR(ZEND_VM_ENTER_BIT))); +} + +static void zend_jit_vm_leave(zend_jit_ctx *jit, ir_ref to_opline) +{ + // ZEND_VM_LEAVE() + ir_RETURN(ir_OR_A(to_opline, ir_CONST_ADDR(ZEND_VM_ENTER_BIT))); +} + /* stubs */ static int zend_jit_exception_handler_stub(zend_jit_ctx *jit) @@ -1929,14 +1903,8 @@ static int zend_jit_exception_handler_stub(zend_jit_ctx *jit) if (GCC_GLOBAL_REGS) { ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler)); } else { - ir_ref ref, if_negative; - - ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), jit_FP(jit)); - if_negative = ir_IF(ir_LT(ref, ir_CONST_U32(0))); - ir_IF_TRUE(if_negative); - ir_MERGE_WITH_EMPTY_FALSE(if_negative); - ref = ir_PHI_2(IR_I32, ref, ir_CONST_I32(1)); - ir_RETURN(ref); + ir_ref ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit)); + zend_jit_vm_enter(jit, ref); } } return 1; @@ -2014,10 +1982,8 @@ static int zend_jit_interrupt_handler_stub(zend_jit_ctx *jit) { ir_ref if_timeout, if_exception; - if (GCC_GLOBAL_REGS) { - // EX(opline) = opline - ir_STORE(jit_EX(opline), jit_IP(jit)); - } + // EX(opline) = opline + ir_STORE(jit_EX(opline), jit_IP(jit)); ir_STORE(jit_EG(vm_interrupt), ir_CONST_U8(0)); if_timeout = ir_IF(ir_EQ(ir_LOAD_U8(jit_EG(timed_out)), ir_CONST_U8(0))); @@ -2039,7 +2005,7 @@ static int zend_jit_interrupt_handler_stub(zend_jit_ctx *jit) if (GCC_GLOBAL_REGS) { ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit))); } else { - ir_RETURN(ir_CONST_I32(1)); + zend_jit_vm_enter(jit, jit_IP(jit)); } return 1; } @@ -2059,7 +2025,7 @@ static int zend_jit_leave_function_handler_stub(zend_jit_ctx *jit) } else if (GCC_GLOBAL_REGS) { ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info); } else { - ir_TAILCALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info, jit_FP(jit)); + ir_TAILCALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), jit_FP(jit), jit_IP(jit), call_info); } ir_IF_TRUE(if_top); @@ -2070,7 +2036,7 @@ static int zend_jit_leave_function_handler_stub(zend_jit_ctx *jit) } else if (GCC_GLOBAL_REGS) { ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info); } else { - ir_TAILCALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info, jit_FP(jit)); + ir_TAILCALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), jit_FP(jit), jit_IP(jit), call_info); } return 1; @@ -2209,9 +2175,7 @@ static int zend_jit_icall_throw_stub(zend_jit_ctx *jit) // JIT: opline = EG(exception_op); jit_STORE_IP(jit, jit_EG(exception_op)); - if (GCC_GLOBAL_REGS) { - ir_STORE(jit_EX(opline), jit_IP(jit)); - } + ir_STORE(jit_EX(opline), jit_IP(jit)); ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler)); @@ -2234,7 +2198,7 @@ static int zend_jit_leave_throw_stub(zend_jit_ctx *jit) ir_MERGE_WITH_EMPTY_TRUE(if_set); // JIT: opline = EG(exception_op); - jit_LOAD_IP(jit, jit_EG(exception_op)); + jit_STORE_IP(jit, jit_EG(exception_op)); if (GCC_GLOBAL_REGS) { ir_STORE(jit_EX(opline), jit_IP(jit)); @@ -2242,7 +2206,7 @@ static int zend_jit_leave_throw_stub(zend_jit_ctx *jit) // JIT: HANDLE_EXCEPTION() ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler)); } else { - ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE + zend_jit_vm_leave(jit, jit_IP(jit)); } return 1; @@ -2339,13 +2303,7 @@ static int zend_jit_hybrid_loop_hot_counter_stub(zend_jit_ctx *jit) static ir_ref _zend_jit_orig_opline_handler(zend_jit_ctx *jit, ir_ref offset) { - ir_ref addr; - - if (GCC_GLOBAL_REGS) { - addr = ir_ADD_A(offset, jit_IP(jit)); - } else { - addr = ir_ADD_A(offset, ir_LOAD_A(jit_EX(opline))); - } + ir_ref addr = ir_ADD_A(offset, jit_IP(jit)); return ir_LOAD_A(addr); } @@ -2433,7 +2391,7 @@ static int zend_jit_trace_halt_stub(zend_jit_ctx *jit) jit_STORE_IP(jit, IR_NULL); ir_RETURN(IR_VOID); } else { - ir_RETURN(ir_CONST_I32(-1)); // ZEND_VM_RETURN + ir_RETURN(ir_CONST_ADDR(ZEND_VM_ENTER_BIT)); // ZEND_VM_RETURN } return 1; } @@ -2443,7 +2401,7 @@ static int zend_jit_trace_escape_stub(zend_jit_ctx *jit) if (GCC_GLOBAL_REGS) { ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit))); } else { - ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER + zend_jit_vm_enter(jit, jit_IP(jit)); } return 1; @@ -2453,10 +2411,8 @@ static int zend_jit_trace_exit_stub(zend_jit_ctx *jit) { ir_ref ref, ret, if_zero, addr; - if (GCC_GLOBAL_REGS) { - // EX(opline) = opline - ir_STORE(jit_EX(opline), jit_IP(jit)); - } + // EX(opline) = opline + ir_STORE(jit_EX(opline), jit_IP(jit)); ret = ir_EXITCALL(ir_CONST_FC_FUNC(zend_jit_trace_exit)); @@ -2464,14 +2420,15 @@ static int zend_jit_trace_exit_stub(zend_jit_ctx *jit) ir_IF_TRUE(if_zero); + ref = jit_EG(current_execute_data); + jit_STORE_FP(jit, ir_LOAD_A(ref)); + ref = ir_LOAD_A(jit_EX(opline)); + jit_STORE_IP(jit, ref); + if (GCC_GLOBAL_REGS) { - ref = jit_EG(current_execute_data); - jit_STORE_FP(jit, ir_LOAD_A(ref)); - ref = ir_LOAD_A(jit_EX(opline)); - jit_STORE_IP(jit, ref); ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit))); } else { - ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER + zend_jit_vm_enter(jit, ref); } ir_IF_FALSE(if_zero); @@ -2481,10 +2438,8 @@ static int zend_jit_trace_exit_stub(zend_jit_ctx *jit) ref = jit_EG(current_execute_data); jit_STORE_FP(jit, ir_LOAD_A(ref)); - if (GCC_GLOBAL_REGS) { - ref = ir_LOAD_A(jit_EX(opline)); - jit_STORE_IP(jit, ref); - } + ref = ir_LOAD_A(jit_EX(opline)); + jit_STORE_IP(jit, ref); // check for interrupt (try to avoid this ???) zend_jit_check_timeout(jit, NULL, NULL); @@ -2496,9 +2451,8 @@ static int zend_jit_trace_exit_stub(zend_jit_ctx *jit) #if defined(IR_TARGET_X86) addr = ir_CAST_FC_FUNC(addr); #endif - ref = ir_CALL_1(IR_I32, addr, jit_FP(jit)); - ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt)); - ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER + ref = ir_CALL_2(IR_ADDR, addr, jit_FP(jit), jit_IP(jit)); + zend_jit_vm_enter(jit, ref); } return 1; @@ -2509,7 +2463,7 @@ static int zend_jit_undefined_offset_stub(zend_jit_ctx *jit) if (GCC_GLOBAL_REGS) { ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key)); } else { - ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key), jit_FP(jit)); + ir_TAILCALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key), jit_FP(jit), jit_IP(jit)); } return 1; @@ -2520,7 +2474,7 @@ static int zend_jit_undefined_key_stub(zend_jit_ctx *jit) if (GCC_GLOBAL_REGS) { ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key)); } else { - ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key), jit_FP(jit)); + ir_TAILCALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key), jit_FP(jit), jit_IP(jit)); } return 1; @@ -2702,6 +2656,10 @@ static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags) #else /* IR_TARGET_x86 */ jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 4 saved registers and 7 spill slots (4 bytes) */ #endif + /* JIT-ed code is called only from execute_ex, which takes care + * of saving ZREG_FP, ZREG_IP when GCC_GLOBAL_REGS is 1, so we don't + * have to save them. + */ if (GCC_GLOBAL_REGS) { jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED & ~((1<ctx.flags |= IR_FASTCALL_FUNC; } @@ -3960,18 +3920,10 @@ static int jit_CMP_IP(zend_jit_ctx *jit, ir_op op, const zend_op *next_opline) ir_ref ref; #if 1 - if (GCC_GLOBAL_REGS) { - ref = jit_IP32(jit); - } else { - ref = ir_LOAD_U32(jit_EX(opline)); - } + ref = jit_IP32(jit); ref = ir_CMP_OP(op, ref, ir_CONST_U32((uint32_t)(uintptr_t)next_opline)); #else - if (GCC_GLOBAL_REGS) { - ref = jit_IP(jit); - } else { - ref = ir_LOAD_A(jit_EX(opline)); - } + ref = jit_IP(jit); ref = ir_CMP_OP(op, ref, ir_CONST_ADDR(next_opline)); #endif return ref; @@ -4144,10 +4096,13 @@ static void zend_jit_recv_entry(zend_jit_ctx *jit, int b) /* Insert a MERGE block with additional ENTRY input between predecessor and this one */ ir_ENTRY(ref, bb->start); if (!GCC_GLOBAL_REGS) { - /* 2 is hardcoded reference to IR_PARAM */ + /* 2 and 3 are hardcoded reference to IR_PARAMs */ ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM); ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1); jit_STORE_FP(jit, 2); + ZEND_ASSERT(jit->ctx.ir_base[3].op == IR_PARAM); + ZEND_ASSERT(jit->ctx.ir_base[3].op3 == 2); + jit_STORE_IP(jit, 3); } ir_MERGE_WITH(ref); @@ -4162,10 +4117,13 @@ static void zend_jit_osr_entry(zend_jit_ctx *jit, int b) /* Insert a MERGE block with additional ENTRY input between predecessor and this one */ ir_ENTRY(ref, bb->start); if (!GCC_GLOBAL_REGS) { - /* 2 is hardcoded reference to IR_PARAM */ + /* 2 and 3 are hardcoded reference to IR_PARAMs */ ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM); ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1); jit_STORE_FP(jit, 2); + ZEND_ASSERT(jit->ctx.ir_base[3].op == IR_PARAM); + ZEND_ASSERT(jit->ctx.ir_base[3].op3 == 2); + jit_STORE_IP(jit, 3); } ir_MERGE_WITH(ref); @@ -4175,17 +4133,19 @@ static ir_ref zend_jit_continue_entry(zend_jit_ctx *jit, ir_ref src, unsigned in { ir_ENTRY(src, label); if (!GCC_GLOBAL_REGS) { - /* 2 is hardcoded reference to IR_PARAM */ + /* 2 and 3 are hardcoded reference to IR_PARAMs */ ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM); ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1); jit_STORE_FP(jit, 2); + ZEND_ASSERT(jit->ctx.ir_base[3].op == IR_PARAM); + ZEND_ASSERT(jit->ctx.ir_base[3].op3 == 2); + jit_STORE_IP(jit, 3); } return ir_END(); } static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_throw) { - ir_ref ref; const void *handler; zend_jit_set_ip(jit, opline); @@ -4197,8 +4157,8 @@ static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_th if (GCC_GLOBAL_REGS) { ir_CALL(IR_VOID, ir_CONST_FUNC(handler)); } else { - ref = jit_FP(jit); - ref = ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(handler), ref); + ir_ref ip = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit)); + jit_STORE_IP(jit, ip); } if (may_throw) { zend_jit_check_exception(jit); @@ -4213,6 +4173,7 @@ static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_th case ZEND_ASSIGN_STATIC_PROP_OP: case ZEND_ASSIGN_STATIC_PROP_REF: case ZEND_ASSIGN_OBJ_REF: + case ZEND_FRAMELESS_ICALL_3: zend_jit_set_last_valid_opline(jit, opline + 2); break; default: @@ -4255,12 +4216,10 @@ static int zend_jit_tail_handler(zend_jit_ctx *jit, const zend_op *opline) || opline->opcode == ZEND_MATCH_ERROR || opline->opcode == ZEND_THROW || opline->opcode == ZEND_VERIFY_NEVER_TYPE)) { - ref = jit_FP(jit); - ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref); - ir_RETURN(ir_CONST_I32(1)); + ir_ref ip = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit)); + zend_jit_vm_enter(jit, ip); } else { - ref = jit_FP(jit); - ir_TAILCALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref); + ir_TAILCALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit)); } } if (jit->b >= 0) { @@ -10152,7 +10111,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen ir_GUARD_NOT( ir_AND_U32( ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))), - ir_CONST_U32(ZEND_ACC_DEPRECATED)), + ir_CONST_U32(ZEND_ACC_DEPRECATED|ZEND_ACC_NODISCARD)), ir_CONST_ADDR(exit_addr)); } } @@ -10178,12 +10137,27 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) { if (!func) { if (!trace) { - ir_ref if_deprecated, ret; + ir_ref if_deprecated_nodiscard, ret; + + uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD; - if_deprecated = ir_IF(ir_AND_U32( + if_deprecated_nodiscard = ir_IF(ir_AND_U32( ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))), - ir_CONST_U32(ZEND_ACC_DEPRECATED))); - ir_IF_TRUE_cold(if_deprecated); + ir_CONST_U32(ZEND_ACC_DEPRECATED|no_discard))); + ir_IF_TRUE_cold(if_deprecated_nodiscard); + + ir_ref helper = ir_CONST_FC_FUNC(no_discard ? zend_jit_deprecated_nodiscard_helper : zend_jit_deprecated_helper); + if (GCC_GLOBAL_REGS) { + ret = ir_CALL(IR_BOOL, helper); + } else { + ret = ir_CALL_1(IR_BOOL, helper, rx); + } + ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler)); + ir_MERGE_WITH_EMPTY_FALSE(if_deprecated_nodiscard); + } + } else { + if (func->common.fn_flags & ZEND_ACC_DEPRECATED) { + ir_ref ret; if (GCC_GLOBAL_REGS) { ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper)); @@ -10191,17 +10165,18 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx); } ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler)); - ir_MERGE_WITH_EMPTY_FALSE(if_deprecated); } - } else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) { - ir_ref ret; - if (GCC_GLOBAL_REGS) { - ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper)); - } else { - ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx); + if ((func->common.fn_flags & ZEND_ACC_NODISCARD) && !RETURN_VALUE_USED(opline)) { + ir_ref ret; + + if (GCC_GLOBAL_REGS) { + ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_nodiscard_helper)); + } else { + ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_nodiscard_helper), rx); + } + ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler)); } - ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler)); } } @@ -10302,7 +10277,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen if (num_args) { ip = ir_ADD_OFFSET(ip, num_args * sizeof(zend_op)); } - jit_LOAD_IP(jit, ip); + jit_STORE_IP(jit, ip); } if (!trace && op_array == &func->op_array && call_num_args >= op_array->required_num_args) { @@ -10324,7 +10299,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen } ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))); } - jit_LOAD_IP(jit, ip); + jit_STORE_IP(jit, ip); helper = ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper); } else { helper = ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper_no_skip_recv); @@ -10332,7 +10307,8 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen if (GCC_GLOBAL_REGS) { ir_CALL(IR_VOID, helper); } else { - ir_CALL_1(IR_VOID, helper, jit_FP(jit)); + ir_ref ref = ir_CALL_2(IR_ADDR, helper, jit_FP(jit), jit_IP(jit)); + jit_STORE_IP(jit, ref); } } } else { @@ -10348,7 +10324,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen } ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))); } - jit_LOAD_IP(jit, ip); + jit_STORE_IP(jit, ip); // JIT: num_args = EX_NUM_ARGS(); ir_ref num_args, first_extra_arg; @@ -10368,7 +10344,8 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen if (GCC_GLOBAL_REGS) { ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper)); } else { - ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit)); + ir_ref ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit), jit_IP(jit)); + jit_STORE_IP(jit, ref); } ir_END_list(merge_inputs); ir_IF_FALSE(if_extra_args); @@ -10390,13 +10367,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen ref = ir_ZEXT_A(ref); } - if (GCC_GLOBAL_REGS) { - jit_STORE_IP(jit, ir_ADD_A(jit_IP(jit), ref)); - } else { - ir_ref addr = jit_EX(opline); - - ir_STORE(addr, ir_ADD_A(ir_LOAD_A(addr), ref)); - } + jit_STORE_IP(jit, ir_ADD_A(jit_IP(jit), ref)); } ir_END_list(merge_inputs); @@ -10445,7 +10416,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) { ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END); jit_SET_EX_OPLINE(jit, trace[1].opline); - } else if (GCC_GLOBAL_REGS) { + } else { // EX(opline) = opline ir_STORE(jit_EX(opline), jit_IP(jit)); } @@ -10512,7 +10483,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen if (GCC_GLOBAL_REGS) { ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit))); } else { - ir_RETURN(ir_CONST_I32(1)); + zend_jit_vm_enter(jit, jit_IP(jit)); } } while (0); @@ -11014,11 +10985,10 @@ static bool zend_jit_verify_return_type(zend_jit_ctx *jit, const zend_op *opline ref = zend_jit_zval_check_undef(jit, ref, opline->op1.var, NULL, 1); } - ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_verify_return_slow), + ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_verify_return_slow), ref, ir_LOAD_A(jit_EX(func)), - ir_CONST_ADDR(arg_info), - ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->op2.num)); + ir_CONST_ADDR(arg_info)); zend_jit_check_exception(jit); @@ -11113,7 +11083,7 @@ static int zend_jit_leave_func(zend_jit_ctx *jit, ir_IF_TRUE_cold(if_slow); if (!GCC_GLOBAL_REGS) { - ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_func_helper), jit_FP(jit)); + ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_leave_func_helper), jit_FP(jit), jit_IP(jit)); } else { ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_func_helper)); } @@ -11129,7 +11099,8 @@ static int zend_jit_leave_func(zend_jit_ctx *jit, } else if (GCC_GLOBAL_REGS) { ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt)); } else { - ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt)); + ir_GUARD(ir_NE(ref, ir_CONST_ADDR(ZEND_VM_ENTER_BIT)), jit_STUB_ADDR(jit, jit_stub_trace_halt)); + jit_STORE_IP(jit, ref); } } @@ -11197,26 +11168,20 @@ static int zend_jit_leave_func(zend_jit_ctx *jit, && (JIT_G(current_frame) && !TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) { zend_jit_reset_last_valid_opline(jit); } else { - if (GCC_GLOBAL_REGS) { - /* We add extra RLOAD and RSTORE to make fusion for persistent register - * mov (%FP), %IP - * add $0x1c, %IP - * The naive (commented) code leads to extra register allocation and move. - * mov (%FP), %tmp - * add $0x1c, %tmp - * mov %tmp, %FP - */ + /* We add extra RLOAD and RSTORE to make fusion for persistent register + * mov (%FP), %IP + * add $0x1c, %IP + * The naive (commented) code leads to extra register allocation and move. + * mov (%FP), %tmp + * add $0x1c, %tmp + * mov %tmp, %FP + */ #if 0 - jit_STORE_IP(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(opline)), sizeof(zend_op))); + jit_STORE_IP(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(opline)), sizeof(zend_op))); #else - jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline))); - jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op))); + jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline))); + jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op))); #endif - } else { - ir_ref ref = jit_EX(opline); - - ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op))); - } } if (cold_path) { @@ -11279,20 +11244,14 @@ static int zend_jit_leave_func(zend_jit_ctx *jit, // JIT: if (EG(exception)) ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw)); // JIT: opline = EX(opline) + 1 - if (GCC_GLOBAL_REGS) { - jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline))); - jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op))); - } else { - ir_ref ref = jit_EX(opline); - - ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op))); - } + jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline))); + jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op))); } if (GCC_GLOBAL_REGS) { ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit))); } else { - ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE + zend_jit_vm_leave(jit, jit_IP(jit)); } jit->b = -1; @@ -13683,6 +13642,13 @@ static int zend_jit_assign_dim_op(zend_jit_ctx *jit, ref_path = ir_END(); ir_IF_TRUE_cold(if_typed); + if (Z_MODE(op3_addr) == IS_REG) { + zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var); + if (!zend_jit_spill_store_inv(jit, op3_addr, real_addr, op1_data_info)) { + return 0; + } + op3_addr = real_addr; + } arg2 = jit_ZVAL_ADDR(jit, op3_addr); ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref), reference, arg2, ir_CONST_FC_FUNC(binary_op)); @@ -14953,13 +14919,6 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, // CACHE_PTR_EX(cache_slot + 2, NULL); } - if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) { - return 0; - } - } - ir_END_list(end_inputs); ir_IF_FALSE(if_has_prop_info); } @@ -15025,12 +14984,6 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, arg3, arg4); - if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) { - return 0; - } - } ir_END_list(end_inputs); } } @@ -15043,7 +14996,14 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, return 0; } } else { - if (!zend_jit_assign_to_variable(jit, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0, 0)) { + zend_jit_addr real_res_addr; + + if (res_addr && Z_MODE(res_addr) == IS_REG) { + real_res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); + } else { + real_res_addr = res_addr; + } + if (!zend_jit_assign_to_variable(jit, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, real_res_addr, 0, 0)) { return 0; } } @@ -15093,12 +15053,6 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS), arg5); - if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) { - return 0; - } - } ir_END_list(end_inputs); } @@ -15119,6 +15073,13 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline); } + if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) { + zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); + if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) { + return 0; + } + } + if (may_throw) { zend_jit_check_exception(jit); } @@ -16727,8 +16688,10 @@ static int zend_jit_start(zend_jit_ctx *jit, const zend_op_array *op_array, zend jit->bb_edges = zend_arena_calloc(&CG(arena), count, sizeof(ir_ref)); if (!GCC_GLOBAL_REGS) { - ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1); - jit_STORE_FP(jit, ref); + ir_ref execute_data_ref = ir_PARAM(IR_ADDR, "execute_data", 1); + ir_ref opline_ref = ir_PARAM(IR_ADDR, "opline", 2); + jit_STORE_FP(jit, execute_data_ref); + jit_STORE_IP(jit, opline_ref); jit->ctx.flags |= IR_FASTCALL_FUNC; } @@ -17111,8 +17074,18 @@ static int zend_jit_trace_handler(zend_jit_ctx *jit, const zend_op_array *op_arr if (GCC_GLOBAL_REGS) { ir_CALL(IR_VOID, ir_CONST_FUNC(handler)); } else { - ref = jit_FP(jit); - ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref); + ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit)); + if (opline->opcode == ZEND_RETURN || + opline->opcode == ZEND_RETURN_BY_REF || + opline->opcode == ZEND_DO_UCALL || + opline->opcode == ZEND_DO_FCALL_BY_NAME || + opline->opcode == ZEND_DO_FCALL || + opline->opcode == ZEND_GENERATOR_CREATE) { + + jit_STORE_IP(jit, ir_AND_A(ref, ir_CONST_ADDR(~ZEND_VM_ENTER_BIT))); + } else { + jit_STORE_IP(jit, ref); + } } if (may_throw && opline->opcode != ZEND_RETURN @@ -17152,10 +17125,9 @@ static int zend_jit_trace_handler(zend_jit_ctx *jit, const zend_op_array *op_arr ir_GUARD(ir_NE(jit_IP(jit), ir_CONST_ADDR(zend_jit_halt_op)), jit_STUB_ADDR(jit, jit_stub_trace_halt)); } - } else if (GCC_GLOBAL_REGS) { - ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt)); } else { - ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt)); + /* IP has been cleared of ZEND_VM_ENTER_BIT already */ + ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt)); } } else if (opline->opcode == ZEND_GENERATOR_RETURN || opline->opcode == ZEND_YIELD || @@ -17291,8 +17263,10 @@ static int zend_jit_trace_start(zend_jit_ctx *jit, if (!GCC_GLOBAL_REGS) { if (!parent) { - ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1); - jit_STORE_FP(jit, ref); + ir_ref execute_data_ref = ir_PARAM(IR_ADDR, "execute_data", 1); + ir_ref opline_ref = ir_PARAM(IR_ADDR, "opline", 2); + jit_STORE_FP(jit, execute_data_ref); + jit_STORE_IP(jit, opline_ref); jit->ctx.flags |= IR_FASTCALL_FUNC; } } @@ -17405,7 +17379,7 @@ static int zend_jit_trace_return(zend_jit_ctx *jit, bool original_handler, const #if defined(IR_TARGET_X86) addr = ir_CAST_FC_FUNC(addr); #endif - ref = ir_CALL_1(IR_I32, addr, jit_FP(jit)); + ref = ir_CALL_2(IR_ADDR, addr, jit_FP(jit), jit_IP(jit)); if (opline && (opline->opcode == ZEND_RETURN || opline->opcode == ZEND_RETURN_BY_REF @@ -17413,11 +17387,11 @@ static int zend_jit_trace_return(zend_jit_ctx *jit, bool original_handler, const || opline->opcode == ZEND_GENERATOR_CREATE || opline->opcode == ZEND_YIELD || opline->opcode == ZEND_YIELD_FROM)) { - ir_RETURN(ref); + zend_jit_vm_enter(jit, ref); return 1; } } - ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE + zend_jit_vm_enter(jit, jit_IP(jit)); } return 1; } diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index d1bc2bdbd77cf..68c096d9d3df2 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -16,6 +16,11 @@ +----------------------------------------------------------------------+ */ +#include "zend_jit.h" +#include "zend_jit_internal.h" +#include "zend_shared_alloc.h" +#include "ir/ir.h" + static zend_jit_trace_info *zend_jit_traces = NULL; static const void **zend_jit_exit_groups = NULL; @@ -7433,7 +7438,7 @@ static const void *zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_n original_handler = 1; } } - zend_jit_set_ip_ex(&ctx, opline, original_handler); + zend_jit_set_ip(&ctx, opline); } zend_jit_trace_return(&ctx, original_handler, opline); diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index b7fb661615d1c..0ce7f082ae15f 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -46,7 +46,7 @@ register const zend_op* volatile opline __asm__("x28"); # pragma GCC diagnostic warning "-Wvolatile-register-var" #endif -ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(uint32_t call_info EXECUTE_DATA_DC) +ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(ZEND_OPCODE_HANDLER_ARGS_EX uint32_t call_info) { zend_execute_data *old_execute_data; @@ -75,19 +75,19 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(uint32_t zval_ptr_dtor(EX_VAR(old_opline->result.var)); } #ifndef HAVE_GCC_GLOBAL_REGS - return 2; // ZEND_VM_LEAVE + return (zend_op*)((uintptr_t)EG(current_execute_data)->opline | ZEND_VM_ENTER_BIT); #endif } else { EX(opline)++; #ifdef HAVE_GCC_GLOBAL_REGS opline = EX(opline); #else - return 2; // ZEND_VM_LEAVE + return (zend_op*)((uintptr_t)EX(opline) | ZEND_VM_ENTER_BIT); #endif } } -ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_top_func_helper(uint32_t call_info EXECUTE_DATA_DC) +ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_top_func_helper(ZEND_OPCODE_HANDLER_ARGS_EX uint32_t call_info) { if (UNEXPECTED(call_info & (ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS))) { if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) { @@ -105,11 +105,11 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_top_func_helper(uint32_t ca #ifdef HAVE_GCC_GLOBAL_REGS opline = zend_jit_halt_op; #else - return -1; // ZEND_VM_RETURN + return (const zend_op*)ZEND_VM_ENTER_BIT; // ZEND_VM_RETURN #endif } -ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_func_helper(EXECUTE_DATA_D) +ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_func_helper(ZEND_OPCODE_HANDLER_ARGS) { uint32_t call_info = EX_CALL_INFO(); @@ -120,7 +120,7 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_func_helper(EXECUTE_DATA_D) } } -static void ZEND_FASTCALL zend_jit_copy_extra_args_helper_ex(bool skip_recv EXECUTE_DATA_DC) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_copy_extra_args_helper_ex(ZEND_OPCODE_HANDLER_ARGS_EX bool skip_recv) { zend_op_array *op_array = &EX(func)->op_array; @@ -132,11 +132,7 @@ static void ZEND_FASTCALL zend_jit_copy_extra_args_helper_ex(bool skip_recv EXEC if (skip_recv && EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) { /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */ -#ifdef HAVE_GCC_GLOBAL_REGS opline += first_extra_arg; -#else - EX(opline) += first_extra_arg; -#endif } /* move extra args into separate array after all CV and TMP vars */ @@ -164,16 +160,20 @@ static void ZEND_FASTCALL zend_jit_copy_extra_args_helper_ex(bool skip_recv EXEC } while (src != end); } } + +#ifndef HAVE_GCC_GLOBAL_REGS + return opline; +#endif } -void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D) +ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_copy_extra_args_helper(ZEND_OPCODE_HANDLER_ARGS) { - zend_jit_copy_extra_args_helper_ex(true EXECUTE_DATA_CC); + return zend_jit_copy_extra_args_helper_ex(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX true); } -void ZEND_FASTCALL zend_jit_copy_extra_args_helper_no_skip_recv(EXECUTE_DATA_D) +ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_copy_extra_args_helper_no_skip_recv(ZEND_OPCODE_HANDLER_ARGS) { - zend_jit_copy_extra_args_helper_ex(false EXECUTE_DATA_CC); + return zend_jit_copy_extra_args_helper_ex(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX false); } bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D) @@ -204,6 +204,54 @@ bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D) return 1; } +bool ZEND_FASTCALL zend_jit_nodiscard_helper(OPLINE_D) +{ + zend_execute_data *call = (zend_execute_data *) opline; + zend_function *fbc = call->func; + + zend_nodiscard_function(fbc); + + if (EG(exception)) { +#ifndef HAVE_GCC_GLOBAL_REGS + zend_execute_data *execute_data = EG(current_execute_data); +#endif + const zend_op *opline = EG(opline_before_exception); + if (opline && RETURN_VALUE_USED(opline)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } + + zend_vm_stack_free_args(call); + + if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) { + OBJ_RELEASE(Z_OBJ(call->This)); + } + + zend_vm_stack_free_call_frame(call); + return 0; + } + return 1; +} + +bool ZEND_FASTCALL zend_jit_deprecated_nodiscard_helper(OPLINE_D) +{ + zend_execute_data *call = (zend_execute_data *) opline; + zend_function *fbc = call->func; + + if (fbc->common.fn_flags & ZEND_ACC_DEPRECATED) { + if (zend_jit_deprecated_helper(OPLINE_C) == 0) { + return 0; + } + } + + if (fbc->common.fn_flags & ZEND_ACC_NODISCARD) { + if (zend_jit_nodiscard_helper(OPLINE_C) == 0) { + return 0; + } + } + + return 1; +} + void ZEND_FASTCALL zend_jit_undefined_long_key(EXECUTE_DATA_D) { const zend_op *opline = EX(opline); @@ -264,9 +312,6 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_counter_helper(ZEND_OPCODE_H { zend_jit_op_array_hot_extension *jit_extension = (zend_jit_op_array_hot_extension*)ZEND_FUNC_INFO(&EX(func)->op_array); -#ifndef HAVE_GCC_GLOBAL_REGS - const zend_op *opline = EX(opline); -#endif *(jit_extension->counter) -= ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)); @@ -284,9 +329,6 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_H { zend_jit_op_array_hot_extension *jit_extension = (zend_jit_op_array_hot_extension*)ZEND_FUNC_INFO(&EX(func)->op_array); -#ifndef HAVE_GCC_GLOBAL_REGS - const zend_op *opline = EX(opline); -#endif *(jit_extension->counter) -= ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)); @@ -355,14 +397,11 @@ zend_constant* ZEND_FASTCALL zend_jit_check_constant(const zval *key) return _zend_quick_get_constant(key, 0, 1); } -static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_trace_counter_helper(uint32_t cost ZEND_OPCODE_HANDLER_ARGS_DC) +static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_trace_counter_helper(ZEND_OPCODE_HANDLER_ARGS_EX uint32_t cost) { zend_jit_op_array_trace_extension *jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(&EX(func)->op_array); size_t offset = jit_extension->offset; -#ifndef HAVE_GCC_GLOBAL_REGS - const zend_op *opline = EX(opline); -#endif *(ZEND_OP_TRACE_INFO(opline, offset)->counter) -= cost; @@ -373,15 +412,15 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_trace_c opline = NULL; return; #else - return -1; + return (const zend_op*)ZEND_VM_ENTER_BIT; // ZEND_VM_RETURN() #endif } -#ifdef HAVE_GCC_GLOBAL_REGS execute_data = EG(current_execute_data); opline = execute_data ? EX(opline) : NULL; +#ifdef HAVE_GCC_GLOBAL_REGS return; #else - return 1; + return (const zend_op*)((uintptr_t)opline | ZEND_VM_ENTER_BIT); // ZEND_VM_ENTER() / ZEND_VM_RETURN() #endif } else { zend_vm_opcode_handler_t handler = (zend_vm_opcode_handler_t)ZEND_OP_TRACE_INFO(opline, offset)->orig_handler; @@ -630,15 +669,14 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, int last_loop_level = -1; const zend_op *last_loop_opline = NULL; const zend_op_array *unrolled_calls[ZEND_JIT_TRACE_MAX_CALL_DEPTH + ZEND_JIT_TRACE_MAX_RET_DEPTH]; -#ifdef HAVE_GCC_GLOBAL_REGS zend_execute_data *prev_execute_data = ex; +#ifdef HAVE_GCC_GLOBAL_REGS execute_data = ex; opline = EX(opline) = op; #else - int rc; zend_execute_data *execute_data = ex; - const zend_op *opline = EX(opline); + const zend_op *opline = EX(opline) = op; #endif zend_execute_data *prev_call = EX(call); @@ -944,40 +982,29 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, #ifdef HAVE_GCC_GLOBAL_REGS handler(); if (UNEXPECTED(opline == zend_jit_halt_op)) { +#else + opline = handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (UNEXPECTED(((uintptr_t)opline & ~ZEND_VM_ENTER_BIT) == 0)) { +#endif stop = ZEND_JIT_TRACE_STOP_RETURN; opline = NULL; halt = ZEND_JIT_TRACE_HALT; break; } - if (UNEXPECTED(execute_data != prev_execute_data)) { -#else - rc = handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - if (rc != 0) { - if (rc < 0) { - stop = ZEND_JIT_TRACE_STOP_RETURN; - opline = NULL; - halt = ZEND_JIT_TRACE_HALT; - break; - } else if (execute_data == EG(current_execute_data)) { - /* return after interrupt handler */ - rc = 0; - } +#ifndef HAVE_GCC_GLOBAL_REGS + if ((uintptr_t)opline & ZEND_VM_ENTER_BIT) { + opline = (const zend_op*)((uintptr_t)opline & ~ZEND_VM_ENTER_BIT); execute_data = EG(current_execute_data); - opline = EX(opline); + } #endif + if (UNEXPECTED(execute_data != prev_execute_data)) { op_array = &EX(func)->op_array; jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array); if (UNEXPECTED(!jit_extension) || UNEXPECTED(!(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE))) { -#ifdef HAVE_GCC_GLOBAL_REGS if (execute_data->prev_execute_data != prev_execute_data) { -#else - if (rc < 0) { -#endif - stop = ZEND_JIT_TRACE_STOP_RETURN; - } else { stop = ZEND_JIT_TRACE_STOP_INTERPRETER; } break; @@ -988,13 +1015,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, op_array = jit_extension->op_array; } -#ifdef HAVE_GCC_GLOBAL_REGS if (execute_data->prev_execute_data == prev_execute_data) { -#else - if (rc == 0) { - /* pass */ - } else if (rc == 1) { -#endif /* Enter into function */ prev_call = NULL; if (level > ZEND_JIT_TRACE_MAX_CALL_DEPTH) { @@ -1116,9 +1137,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, TRACE_RECORD(ZEND_JIT_TRACE_BACK, 0, op_array); } } -#ifdef HAVE_GCC_GLOBAL_REGS prev_execute_data = execute_data; -#endif } if (EX(call) != prev_call) { if (EX(call) @@ -1143,10 +1162,6 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, } } -#ifndef HAVE_GCC_GLOBAL_REGS - opline = EX(opline); -#endif - if (!func || (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) || (func->common.fn_flags & ZEND_ACC_NEVER_CACHE) @@ -1171,10 +1186,6 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, prev_call = EX(call); } -#ifndef HAVE_GCC_GLOBAL_REGS - opline = EX(opline); -#endif - if (UNEXPECTED(opline->opcode == ZEND_HANDLE_EXCEPTION)) { /* Abort trace because of exception */ stop = ZEND_JIT_TRACE_STOP_EXCEPTION; @@ -1298,11 +1309,9 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, TRACE_END(ZEND_JIT_TRACE_END, stop, end_opline); -#ifdef HAVE_GCC_GLOBAL_REGS if (!halt) { EX(opline) = opline; } -#endif #ifdef HAVE_GCC_GLOBAL_REGS execute_data = save_execute_data; diff --git a/ext/opcache/tests/gh18050.phpt b/ext/opcache/tests/gh18050.phpt new file mode 100644 index 0000000000000..d71bc4c4d750f --- /dev/null +++ b/ext/opcache/tests/gh18050.phpt @@ -0,0 +1,66 @@ +--TEST-- +GH-18050: Frameless calls break IN_ARRAY optimization +--EXTENSIONS-- +opcache +--INI-- +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x20000 +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=%d, args=%d, vars=%d, tmps=%d) + ; (after optimizer) + ; %sgh18050.php:%s +0000 INIT_FCALL 1 %d string("test") +0001 SEND_VAL string("x") 1 +0002 DO_UCALL +0003 INIT_FCALL 1 %d string("test") +0004 SEND_VAL string("z") 1 +0005 DO_UCALL +0006 RETURN int(1) + +test: + ; (lines=%d, args=%d, vars=%d, tmps=%d) + ; (after optimizer) + ; %sgh18050.php:%s +0000 CV0($v) = RECV 1 +0001 INIT_FCALL 1 %d string("var_dump") +0002 T1 = IN_ARRAY 0 CV0($v) array(...) +0003 SEND_VAL T1 1 +0004 DO_ICALL +0005 INIT_FCALL 1 %d string("var_dump") +0006 T1 = IN_ARRAY 0 CV0($v) array(...) +0007 SEND_VAL T1 1 +0008 DO_ICALL +0009 INIT_FCALL 1 %d string("var_dump") +0010 T1 = IN_ARRAY 1 CV0($v) array(...) +0011 SEND_VAL T1 1 +0012 DO_ICALL +0013 T1 = IN_ARRAY 1 CV0($v) array(...) +0014 JMPZ T1 0016 +0015 ECHO string("True\n") +0016 RETURN null +bool(true) +bool(true) +bool(true) +True +bool(false) +bool(false) +bool(false) diff --git a/ext/opcache/tests/jit/fetch_obj_001.phpt b/ext/opcache/tests/jit/fetch_obj_001.phpt index 0f68c1aae0991..ddc8dfafba648 100644 --- a/ext/opcache/tests/jit/fetch_obj_001.phpt +++ b/ext/opcache/tests/jit/fetch_obj_001.phpt @@ -96,7 +96,7 @@ object(stdClass)#%d (2) { } object(stdClass)#%d (2) { ["a"]=> - &resource(5) of type (stream) + &resource(%d) of type (stream) ["b"]=> array(0) { } @@ -122,7 +122,7 @@ object(stdClass)#%d (2) { } object(stdClass)#%d (2) { ["a"]=> - &resource(6) of type (stream) + &resource(%d) of type (stream) ["b"]=> array(0) { } diff --git a/ext/opcache/tests/jit/gh17190.phpt b/ext/opcache/tests/jit/gh17190.phpt index d4bb4372b9215..9027050ed6897 100644 --- a/ext/opcache/tests/jit/gh17190.phpt +++ b/ext/opcache/tests/jit/gh17190.phpt @@ -7,7 +7,9 @@ opcache.enable=1 opcache.enable_cli=1 opcache.file_update_protection=0 opcache.jit_buffer_size=32M -opcache.jit=function +opcache.jit=1254 +opcache.jit_hot_func=1 +opcache.jit_hot_side_exit=1 --FILE-- matches(); +} + +test_helper(); +?> +--EXPECTF-- +Warning: Undefined array key 0 in %s on line %d + +Fatal error: Uncaught Error: Call to a member function matches() on array in %s:%d +Stack trace: +#0 %s(%d): test_helper() +#1 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/jit/gh18113.phpt b/ext/opcache/tests/jit/gh18113.phpt new file mode 100644 index 0000000000000..194bb403032b9 --- /dev/null +++ b/ext/opcache/tests/jit/gh18113.phpt @@ -0,0 +1,47 @@ +--TEST-- +GH-18113 (stack-buffer-overflow ext/opcache/jit/ir/ir_sccp.c) +--EXTENSIONS-- +opcache +--INI-- +opcache.jit=1205 +--FILE-- + +--EXPECT-- +Done diff --git a/ext/opcache/tests/jit/gh18136.phpt b/ext/opcache/tests/jit/gh18136.phpt new file mode 100644 index 0000000000000..e1993440003e5 --- /dev/null +++ b/ext/opcache/tests/jit/gh18136.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-18136 (tracing JIT floating point register clobbering on Windows and ARM64) +--EXTENSIONS-- +opcache +--INI-- +opcache.jit=tracing +opcache.jit_buffer_size=64M +opcache.jit_hot_func=4 +opcache.jit_hot_loop=4 +--FILE-- + +--EXPECT-- +float(-347.3205211468715) diff --git a/ext/opcache/tests/jit/gh18294.phpt b/ext/opcache/tests/jit/gh18294.phpt new file mode 100644 index 0000000000000..a3e99e8e7bf0c --- /dev/null +++ b/ext/opcache/tests/jit/gh18294.phpt @@ -0,0 +1,37 @@ +--TEST-- +GH-18294 (assertion failure zend_jit_ir.c) +--EXTENSIONS-- +opcache +--INI-- +opcache.jit=1152 +opcache.jit_hot_func=1 +opcache.jit_hot_side_exit=1 +--FILE-- +>= $overflow; + } + } + return $fusion; +} +?> +--EXPECT-- +Array +( + [1] => 0 + [2] => 0 + [3] => 0 + [4] => 0 + [5] => 0 + [6] => 0 + [7] => 0 + [8] => 0 +) diff --git a/ext/opcache/tests/nodiscard_001.phpt b/ext/opcache/tests/nodiscard_001.phpt new file mode 100644 index 0000000000000..7e232f8f44e41 --- /dev/null +++ b/ext/opcache/tests/nodiscard_001.phpt @@ -0,0 +1,63 @@ +--TEST-- +#[\NoDiscard]: Functions with known-used result use DO_[IU]CALL opcodes +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x20000 +--EXTENSIONS-- +opcache +zend_test +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=17, args=0, vars=2, tmps=%d) + ; (after optimizer) + ; %s +0000 INIT_FCALL 0 %d string("zend_test_nodiscard") +0001 DO_FCALL_BY_NAME +0002 INIT_FCALL 0 %d string("zend_test_nodiscard") +0003 V2 = DO_ICALL +0004 FREE V2 +0005 INIT_FCALL 0 %d string("zend_test_nodiscard") +0006 V2 = DO_ICALL +0007 ASSIGN CV0($success) V2 +0008 INIT_FCALL 0 %d string("test") +0009 DO_FCALL_BY_NAME +0010 INIT_FCALL 0 %d string("test") +0011 V2 = DO_UCALL +0012 FREE V2 +0013 INIT_FCALL 0 %d string("test") +0014 V2 = DO_UCALL +0015 ASSIGN CV1($obj) V2 +0016 RETURN int(1) + +test: + ; (lines=3, args=0, vars=0, tmps=%d) + ; (after optimizer) + ; %s +0000 V0 = NEW 0 string("stdClass") +0001 DO_FCALL +0002 RETURN V0 +LIVE RANGES: + 0: 0001 - 0002 (new) + +Warning: The return value of function zend_test_nodiscard() should either be used or intentionally ignored by casting it as (void), custom message in %s on line %d + +Warning: The return value of function test() should either be used or intentionally ignored by casting it as (void) in %s on line %d diff --git a/ext/opcache/tests/opt/gh18107_1.phpt b/ext/opcache/tests/opt/gh18107_1.phpt new file mode 100644 index 0000000000000..c99fa7efa40d3 --- /dev/null +++ b/ext/opcache/tests/opt/gh18107_1.phpt @@ -0,0 +1,47 @@ +--TEST-- +GH-18107 (Opcache CFG jmp optimization with try-finally breaks the exception table) +--CREDITS-- +SpencerMalone +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=0x10 +opcache.opt_debug_level=0x20000 +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=%d, args=0, vars=%d, tmps=%d) + ; (after optimizer) + ; %s +0000 T1 = ISSET_ISEMPTY_CV (isset) CV0($badvar) +0001 JMPNZ T1 0006 +0002 V3 = NEW 1 string("Exception") +0003 SEND_VAL_EX string("Should happen") 1 +0004 DO_FCALL +0005 THROW V3 +0006 JMP 0006 +0007 V6 = NEW 1 string("Exception") +0008 SEND_VAL_EX string("Should not happen") 1 +0009 DO_FCALL +0010 THROW V6 +0011 FAST_RET T5 +EXCEPTION TABLE: + 0006, -, 0007, 0011 +Fatal error: Uncaught Exception: Should happen in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/opt/gh18107_2.phpt b/ext/opcache/tests/opt/gh18107_2.phpt new file mode 100644 index 0000000000000..573bcd5ae4a6f --- /dev/null +++ b/ext/opcache/tests/opt/gh18107_2.phpt @@ -0,0 +1,54 @@ +--TEST-- +GH-18107 (Opcache CFG jmp optimization with try-finally breaks the exception table) +--CREDITS-- +SpencerMalone +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=0x10 +opcache.opt_debug_level=0x20000 +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=%d, args=0, vars=%d, tmps=%d) + ; (after optimizer) + ; %s +0000 T2 = ISSET_ISEMPTY_CV (isset) CV0($badvar) +0001 JMPNZ T2 0008 +0002 V4 = NEW 1 string("Exception") +0003 SEND_VAL_EX string("Should happen") 1 +0004 DO_FCALL +0005 THROW V4 +0006 CV1($e) = CATCH string("Throwable") +0007 ECHO string("foo") +0008 T6 = FAST_CALL 0010 +0009 JMP 0015 +0010 V7 = NEW 1 string("Exception") +0011 SEND_VAL_EX string("Should not happen") 1 +0012 DO_FCALL +0013 THROW V7 +0014 FAST_RET T6 +0015 RETURN int(1) +EXCEPTION TABLE: + 0006, 0006, 0010, 0014 +Fatal error: Uncaught Exception: Should happen in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index e612dcd80748b..d2b714d937dac 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -242,6 +242,15 @@ static void zend_file_cache_unserialize_zval(zval *zv, zend_persistent_script *script, void *buf); +static void zend_file_cache_serialize_func(zval *zv, + zend_persistent_script *script, + zend_file_cache_metainfo *info, + void *buf); + +static void zend_file_cache_unserialize_func(zval *zv, + zend_persistent_script *script, + void *buf); + static void *zend_file_cache_serialize_interned(zend_string *str, zend_file_cache_metainfo *info) { @@ -364,8 +373,10 @@ static void zend_file_cache_serialize_ast(zend_ast *ast, } } } else if (ast->kind == ZEND_AST_OP_ARRAY) { - /* The op_array itself will be serialized as part of the dynamic_func_defs. */ - SERIALIZE_PTR(zend_ast_get_op_array(ast)->op_array); + zval z; + ZVAL_PTR(&z, zend_ast_get_op_array(ast)->op_array); + zend_file_cache_serialize_func(&z, script, info, buf); + zend_ast_get_op_array(ast)->op_array = Z_PTR(z); } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) { zend_ast_fcc *fcc = (zend_ast_fcc*)ast; ZEND_MAP_PTR_INIT(fcc->fptr, NULL); @@ -457,7 +468,7 @@ static void zend_file_cache_serialize_type( UNSERIALIZE_PTR(list); zend_type *list_type; - ZEND_TYPE_LIST_FOREACH(list, list_type) { + ZEND_TYPE_LIST_FOREACH_MUTABLE(list, list_type) { zend_file_cache_serialize_type(list_type, script, info, buf); } ZEND_TYPE_LIST_FOREACH_END(); } else if (ZEND_TYPE_HAS_NAME(*type)) { @@ -1252,8 +1263,10 @@ static void zend_file_cache_unserialize_ast(zend_ast *ast, } } } else if (ast->kind == ZEND_AST_OP_ARRAY) { - /* The op_array itself will be unserialized as part of the dynamic_func_defs. */ - UNSERIALIZE_PTR(zend_ast_get_op_array(ast)->op_array); + zval z; + ZVAL_PTR(&z, zend_ast_get_op_array(ast)->op_array); + zend_file_cache_unserialize_func(&z, script, buf); + zend_ast_get_op_array(ast)->op_array = Z_PTR(z); } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) { zend_ast_fcc *fcc = (zend_ast_fcc*)ast; ZEND_MAP_PTR_NEW(fcc->fptr); @@ -1335,7 +1348,7 @@ static void zend_file_cache_unserialize_type( ZEND_TYPE_SET_PTR(*type, list); zend_type *list_type; - ZEND_TYPE_LIST_FOREACH(list, list_type) { + ZEND_TYPE_LIST_FOREACH_MUTABLE(list, list_type) { zend_file_cache_unserialize_type(list_type, scope, script, buf); } ZEND_TYPE_LIST_FOREACH_END(); } else if (ZEND_TYPE_HAS_NAME(*type)) { diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 3d45c63a98781..a384cdd2b9a06 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -367,7 +367,7 @@ static void zend_persist_type(zend_type *type) { } zend_type *single_type; - ZEND_TYPE_FOREACH(*type, single_type) { + ZEND_TYPE_FOREACH_MUTABLE(*type, single_type) { if (ZEND_TYPE_HAS_LIST(*single_type)) { zend_persist_type(single_type); continue; diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index bb4f9c7170f28..42a6cf76d62da 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -197,7 +197,7 @@ static void zend_persist_type_calc(zend_type *type) } zend_type *single_type; - ZEND_TYPE_FOREACH(*type, single_type) { + ZEND_TYPE_FOREACH_MUTABLE(*type, single_type) { if (ZEND_TYPE_HAS_LIST(*single_type)) { zend_persist_type_calc(single_type); continue; diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 919431e113092..b17159d46aabc 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -2752,8 +2752,8 @@ PHP_FUNCTION(openssl_pkcs7_read) BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); - BIO_free(bio_out); } + BIO_free(bio_out); } } @@ -2767,8 +2767,8 @@ PHP_FUNCTION(openssl_pkcs7_read) BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); - BIO_free(bio_out); } + BIO_free(bio_out); } } @@ -3393,8 +3393,8 @@ PHP_FUNCTION(openssl_cms_read) BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); - BIO_free(bio_out); } + BIO_free(bio_out); } } @@ -3408,8 +3408,8 @@ PHP_FUNCTION(openssl_cms_read) BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); - BIO_free(bio_out); } + BIO_free(bio_out); } } @@ -3968,26 +3968,18 @@ PHP_FUNCTION(openssl_sign) mdtype = php_openssl_get_evp_md_from_algo(method_long); } if (!mdtype && (!can_default_digest || method_long != 0)) { + EVP_PKEY_free(pkey); php_error_docref(NULL, E_WARNING, "Unknown digest algorithm"); RETURN_FALSE; } md_ctx = EVP_MD_CTX_create(); size_t siglen; -#if PHP_OPENSSL_API_VERSION >= 0x10100 if (md_ctx != NULL && EVP_DigestSignInit(md_ctx, NULL, mdtype, NULL, pkey) && EVP_DigestSign(md_ctx, NULL, &siglen, (unsigned char*)data, data_len) && (sigbuf = zend_string_alloc(siglen, 0)) != NULL && EVP_DigestSign(md_ctx, (unsigned char*)ZSTR_VAL(sigbuf), &siglen, (unsigned char*)data, data_len)) { -#else - if (md_ctx != NULL && - EVP_SignInit(md_ctx, mdtype) && - EVP_SignUpdate(md_ctx, data, data_len) && - (siglen = EVP_PKEY_size(pkey)) && - (sigbuf = zend_string_alloc(siglen, 0)) != NULL && - EVP_SignFinal(md_ctx, (unsigned char*)ZSTR_VAL(sigbuf), (unsigned int*)&siglen, pkey)) { -#endif ZSTR_VAL(sigbuf)[siglen] = '\0'; ZSTR_LEN(sigbuf) = siglen; ZEND_TRY_ASSIGN_REF_NEW_STR(signature, sigbuf); @@ -4048,14 +4040,8 @@ PHP_FUNCTION(openssl_verify) md_ctx = EVP_MD_CTX_create(); if (md_ctx == NULL || -#if PHP_OPENSSL_API_VERSION >= 0x10100 !EVP_DigestVerifyInit(md_ctx, NULL, mdtype, NULL, pkey) || (err = EVP_DigestVerify(md_ctx, (unsigned char *)signature, signature_len, (unsigned char*)data, data_len)) < 0) { -#else - !EVP_VerifyInit (md_ctx, mdtype) || - !EVP_VerifyUpdate (md_ctx, data, data_len) || - (err = EVP_VerifyFinal(md_ctx, (unsigned char *)signature, (unsigned int)signature_len, pkey)) < 0) { -#endif php_openssl_store_errors(); } EVP_MD_CTX_destroy(md_ctx); @@ -4471,17 +4457,15 @@ PHP_FUNCTION(openssl_random_pseudo_bytes) RETURN_THROWS(); } - if (zstrong_result_returned) { - ZEND_TRY_ASSIGN_REF_FALSE(zstrong_result_returned); - } - if ((buffer = php_openssl_random_pseudo_bytes(buffer_length))) { ZSTR_VAL(buffer)[buffer_length] = 0; RETVAL_NEW_STR(buffer); - } - if (zstrong_result_returned) { - ZEND_TRY_ASSIGN_REF_TRUE(zstrong_result_returned); + if (zstrong_result_returned) { + ZEND_TRY_ASSIGN_REF_TRUE(zstrong_result_returned); + } + } else if (zstrong_result_returned) { + ZEND_TRY_ASSIGN_REF_FALSE(zstrong_result_returned); } } /* }}} */ diff --git a/ext/openssl/openssl.stub.php b/ext/openssl/openssl.stub.php index 1f8c6f7fbdbec..1fe3a9fc168eb 100644 --- a/ext/openssl/openssl.stub.php +++ b/ext/openssl/openssl.stub.php @@ -86,14 +86,6 @@ */ const OPENSSL_ALGO_MD2 = UNKNOWN; #endif -#if PHP_OPENSSL_API_VERSION < 0x10100 -/** - * @var int - * @cvalue OPENSSL_ALGO_DSS1 - */ -const OPENSSL_ALGO_DSS1 = UNKNOWN; -#endif - /** * @var int * @cvalue OPENSSL_ALGO_SHA224 diff --git a/ext/openssl/openssl_arginfo.h b/ext/openssl/openssl_arginfo.h index 04d7c4163db9d..94f59ce268510 100644 --- a/ext/openssl/openssl_arginfo.h +++ b/ext/openssl/openssl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 32bd0ec5db046bfe3bba8a5d3fe1c0c51ff89e00 */ + * Stub hash: a42bd7dec0a5e011983ce08b5e31cd8718247501 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 2, _IS_BOOL, 0) ZEND_ARG_OBJ_TYPE_MASK(0, certificate, OpenSSLCertificate, MAY_BE_STRING, NULL) @@ -564,9 +564,6 @@ static void register_openssl_symbols(int module_number) #endif #if !defined(OPENSSL_NO_MD2) REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD2", OPENSSL_ALGO_MD2, CONST_PERSISTENT); -#endif -#if PHP_OPENSSL_API_VERSION < 0x10100 - REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA224", OPENSSL_ALGO_SHA224, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA256", OPENSSL_ALGO_SHA256, CONST_PERSISTENT); diff --git a/ext/openssl/openssl_backend_common.c b/ext/openssl/openssl_backend_common.c index 8fcb81f9a027e..44cb22e18d2ab 100644 --- a/ext/openssl/openssl_backend_common.c +++ b/ext/openssl/openssl_backend_common.c @@ -461,7 +461,6 @@ zend_result php_openssl_write_rand_file(const char * file, int egdsocket, int se if (file == NULL) { file = RAND_file_name(buffer, sizeof(buffer)); } - PHP_OPENSSL_RAND_ADD_TIME(); if (file == NULL || !RAND_write_file(file)) { php_openssl_store_errors(); php_error_docref(NULL, E_WARNING, "Unable to write random state"); @@ -489,11 +488,6 @@ EVP_MD * php_openssl_get_evp_md_from_algo(zend_long algo) { case OPENSSL_ALGO_MD2: mdtype = (EVP_MD *) EVP_md2(); break; -#endif -#if PHP_OPENSSL_API_VERSION < 0x10100 - case OPENSSL_ALGO_DSS1: - mdtype = (EVP_MD *) EVP_dss1(); - break; #endif case OPENSSL_ALGO_SHA224: mdtype = (EVP_MD *) EVP_sha224(); @@ -1510,7 +1504,6 @@ EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req) int egdsocket, seeded; char *randfile = php_openssl_conf_get_string(req->req_config, req->section_name, "RANDFILE"); php_openssl_load_rand_file(randfile, &egdsocket, &seeded); - PHP_OPENSSL_RAND_ADD_TIME(); EVP_PKEY *key = NULL; EVP_PKEY *params = NULL; @@ -1700,48 +1693,25 @@ void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EV int cipher_mode = EVP_CIPHER_mode(cipher_type); memset(mode, 0, sizeof(struct php_openssl_cipher_mode)); switch (cipher_mode) { -#if PHP_OPENSSL_API_VERSION >= 0x10100 - /* Since OpenSSL 1.1, all AEAD ciphers use a common framework. We check for - * EVP_CIPH_OCB_MODE, because LibreSSL does not support it. */ case EVP_CIPH_GCM_MODE: case EVP_CIPH_CCM_MODE: -# ifdef EVP_CIPH_OCB_MODE + /* We check for EVP_CIPH_OCB_MODE, because LibreSSL does not support it. */ +#ifdef EVP_CIPH_OCB_MODE case EVP_CIPH_OCB_MODE: /* For OCB mode, explicitly set the tag length even when decrypting, * see https://github.com/openssl/openssl/issues/8331. */ mode->set_tag_length_always = cipher_mode == EVP_CIPH_OCB_MODE; -# endif +#endif php_openssl_set_aead_flags(mode); mode->set_tag_length_when_encrypting = cipher_mode == EVP_CIPH_CCM_MODE; mode->is_single_run_aead = cipher_mode == EVP_CIPH_CCM_MODE; break; -# ifdef NID_chacha20_poly1305 +#ifdef NID_chacha20_poly1305 default: if (EVP_CIPHER_nid(cipher_type) == NID_chacha20_poly1305) { php_openssl_set_aead_flags(mode); } break; - -# endif -#else -# ifdef EVP_CIPH_GCM_MODE - case EVP_CIPH_GCM_MODE: - mode->is_aead = 1; - mode->aead_get_tag_flag = EVP_CTRL_GCM_GET_TAG; - mode->aead_set_tag_flag = EVP_CTRL_GCM_SET_TAG; - mode->aead_ivlen_flag = EVP_CTRL_GCM_SET_IVLEN; - break; -# endif -# ifdef EVP_CIPH_CCM_MODE - case EVP_CIPH_CCM_MODE: - mode->is_aead = 1; - mode->is_single_run_aead = 1; - mode->set_tag_length_when_encrypting = 1; - mode->aead_get_tag_flag = EVP_CTRL_CCM_GET_TAG; - mode->aead_set_tag_flag = EVP_CTRL_CCM_SET_TAG; - mode->aead_ivlen_flag = EVP_CTRL_CCM_SET_IVLEN; - break; -# endif #endif } } @@ -2121,13 +2091,11 @@ PHP_OPENSSL_API zend_string* php_openssl_random_pseudo_bytes(zend_long buffer_le buffer = zend_string_alloc(buffer_length, 0); PHP_OPENSSL_CHECK_LONG_TO_INT_NULL_RETURN(buffer_length, length); - PHP_OPENSSL_RAND_ADD_TIME(); if (RAND_bytes((unsigned char*)ZSTR_VAL(buffer), (int)buffer_length) <= 0) { + php_openssl_store_errors(); zend_string_release_ex(buffer, 0); zend_throw_exception(zend_ce_exception, "Error reading from source device", 0); return NULL; - } else { - php_openssl_store_errors(); } return buffer; diff --git a/ext/openssl/openssl_backend_v1.c b/ext/openssl/openssl_backend_v1.c index e00b0962fd8d7..59988451bbbd0 100644 --- a/ext/openssl/openssl_backend_v1.c +++ b/ext/openssl/openssl_backend_v1.c @@ -27,159 +27,16 @@ #include #endif -/* OpenSSL compatibility functions and macros */ -#if PHP_OPENSSL_API_VERSION < 0x10100 - -#define EVP_PKEY_get0_RSA(_pkey) _pkey->pkey.rsa -#define EVP_PKEY_get0_DH(_pkey) _pkey->pkey.dh -#define EVP_PKEY_get0_DSA(_pkey) _pkey->pkey.dsa -#define EVP_PKEY_get0_EC_KEY(_pkey) _pkey->pkey.ec - -static int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) -{ - r->n = n; - r->e = e; - r->d = d; - - return 1; -} - -static int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q) -{ - r->p = p; - r->q = q; - - return 1; -} - -static int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp) -{ - r->dmp1 = dmp1; - r->dmq1 = dmq1; - r->iqmp = iqmp; - - return 1; -} - -static void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) -{ - *n = r->n; - *e = r->e; - *d = r->d; -} - -static void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q) -{ - *p = r->p; - *q = r->q; -} - -static void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp) -{ - *dmp1 = r->dmp1; - *dmq1 = r->dmq1; - *iqmp = r->iqmp; -} - -static void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) -{ - *p = dh->p; - *q = dh->q; - *g = dh->g; -} - -static int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) -{ - dh->p = p; - dh->q = q; - dh->g = g; - - return 1; -} - -static void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) -{ - *pub_key = dh->pub_key; - *priv_key = dh->priv_key; -} - -static int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) -{ - dh->pub_key = pub_key; - dh->priv_key = priv_key; - - return 1; -} - -static void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) -{ - *p = d->p; - *q = d->q; - *g = d->g; -} - -int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) -{ - d->p = p; - d->q = q; - d->g = g; - - return 1; -} - -static void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key) -{ - *pub_key = d->pub_key; - *priv_key = d->priv_key; -} - -int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) -{ - d->pub_key = pub_key; - d->priv_key = priv_key; - - return 1; -} - -static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) -{ - return M_ASN1_STRING_data(asn1); -} - -static int EVP_PKEY_up_ref(EVP_PKEY *pkey) -{ - return CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); -} - -#if PHP_OPENSSL_API_VERSION < 0x10002 - -static int X509_get_signature_nid(const X509 *x) -{ - return OBJ_obj2nid(x->sig_alg->algorithm); -} - -#endif - -#define OpenSSL_version SSLeay_version -#define OPENSSL_VERSION SSLEAY_VERSION -#define X509_getm_notBefore X509_get_notBefore -#define X509_getm_notAfter X509_get_notAfter -#define EVP_CIPHER_CTX_reset EVP_CIPHER_CTX_cleanup - -#endif - void php_openssl_backend_shutdown(void) { - #ifdef LIBRESSL_VERSION_NUMBER +#ifdef LIBRESSL_VERSION_NUMBER EVP_cleanup(); /* prevent accessing locking callback from unloaded extension */ CRYPTO_set_locking_callback(NULL); -#ifndef OPENSSL_NO_ENGINE /* Free engine list initialized by OPENSSL_config */ ENGINE_cleanup(); -#endif /* free allocated error strings */ ERR_free_strings(); @@ -259,7 +116,6 @@ static bool php_openssl_pkey_init_dsa_data(DSA *dsa, zval *data, bool *is_privat } /* generate key */ - PHP_OPENSSL_RAND_ADD_TIME(); if (!DSA_generate_key(dsa)) { php_openssl_store_errors(); return 0; @@ -328,7 +184,6 @@ static bool php_openssl_pkey_init_dh_data(DH *dh, zval *data, bool *is_private) } /* generate key */ - PHP_OPENSSL_RAND_ADD_TIME(); if (!DH_generate_key(dh)) { php_openssl_store_errors(); return 0; @@ -484,7 +339,6 @@ static bool php_openssl_pkey_init_ec_data(EC_KEY *eckey, zval *data, bool *is_pr if (!EC_KEY_check_key(eckey)) { *is_private = true; - PHP_OPENSSL_RAND_ADD_TIME(); EC_KEY_generate_key(eckey); } diff --git a/ext/openssl/openssl_backend_v3.c b/ext/openssl/openssl_backend_v3.c index b4508b070c738..76965d66e65a7 100644 --- a/ext/openssl/openssl_backend_v3.c +++ b/ext/openssl/openssl_backend_v3.c @@ -143,7 +143,6 @@ EVP_PKEY *php_openssl_pkey_init_dsa(zval *data, bool *is_private) pkey = param_key; } else { *is_private = true; - PHP_OPENSSL_RAND_ADD_TIME(); EVP_PKEY_CTX_free(ctx); ctx = EVP_PKEY_CTX_new(param_key, NULL); if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_keygen(ctx, &pkey) <= 0) { @@ -219,7 +218,6 @@ EVP_PKEY *php_openssl_pkey_init_dh(zval *data, bool *is_private) pkey = param_key; } else { *is_private = true; - PHP_OPENSSL_RAND_ADD_TIME(); EVP_PKEY_CTX_free(ctx); ctx = EVP_PKEY_CTX_new(param_key, NULL); if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_keygen(ctx, &pkey) <= 0) { @@ -407,7 +405,6 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) { pkey = param_key; } else { *is_private = true; - PHP_OPENSSL_RAND_ADD_TIME(); if (EVP_PKEY_keygen_init(ctx) != 1 || EVP_PKEY_CTX_set_params(ctx, params) != 1 || EVP_PKEY_generate(ctx, &pkey) != 1) { @@ -482,7 +479,6 @@ void php_openssl_pkey_object_curve_25519_448(zval *return_value, int key_type, z is_private = priv_key != NULL; } else { is_private = true; - PHP_OPENSSL_RAND_ADD_TIME(); if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_keygen(ctx, &pkey) <= 0) { goto cleanup; } diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h index 3f408926bc493..bc101539d1b1e 100644 --- a/ext/openssl/php_openssl.h +++ b/ext/openssl/php_openssl.h @@ -26,23 +26,15 @@ extern zend_module_entry openssl_module_entry; #define PHP_OPENSSL_VERSION PHP_VERSION #include -#ifdef LIBRESSL_VERSION_NUMBER -/* LibreSSL version check */ -#if LIBRESSL_VERSION_NUMBER < 0x20700000L -#define PHP_OPENSSL_API_VERSION 0x10001 -#else -#define PHP_OPENSSL_API_VERSION 0x10100 -#endif -#else /* OpenSSL version check */ #if OPENSSL_VERSION_NUMBER < 0x30000000L +/* This includes LibreSSL that defines version 0x20000000L */ #define PHP_OPENSSL_API_VERSION 0x10100 #elif OPENSSL_VERSION_NUMBER < 0x30200000L #define PHP_OPENSSL_API_VERSION 0x30000 #else #define PHP_OPENSSL_API_VERSION 0x30200 #endif -#endif #define OPENSSL_RAW_DATA 1 #define OPENSSL_ZERO_PADDING 2 diff --git a/ext/openssl/php_openssl_backend.h b/ext/openssl/php_openssl_backend.h index f48e3b0761ffb..158b4e27712f9 100644 --- a/ext/openssl/php_openssl_backend.h +++ b/ext/openssl/php_openssl_backend.h @@ -118,9 +118,7 @@ enum php_openssl_encoding { #ifndef OPENSSL_NO_MD2 #define OPENSSL_ALGO_MD2 4 #endif -#if PHP_OPENSSL_API_VERSION < 0x10100 -#define OPENSSL_ALGO_DSS1 5 -#endif +/* Number 5 was used for OPENSSL_ALGO_DSS1 which is no longer available */ #define OPENSSL_ALGO_SHA224 6 #define OPENSSL_ALGO_SHA256 7 #define OPENSSL_ALGO_SHA384 8 @@ -220,23 +218,6 @@ const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo); int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args); void php_openssl_dispose_config(struct php_x509_request * req); - -#if defined(PHP_WIN32) || PHP_OPENSSL_API_VERSION >= 0x10100 -#define PHP_OPENSSL_RAND_ADD_TIME() ((void) 0) -#else -#define PHP_OPENSSL_RAND_ADD_TIME() php_openssl_rand_add_timeval() - -static inline void php_openssl_rand_add_timeval(void) /* {{{ */ -{ - struct timeval tv; - - gettimeofday(&tv, NULL); - RAND_add(&tv, sizeof(tv), 0.0); -} -/* }}} */ - -#endif - zend_result php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded); zend_result php_openssl_write_rand_file(const char * file, int egdsocket, int seeded); @@ -279,7 +260,7 @@ X509_REQ *php_openssl_csr_from_str(zend_string *csr_str, uint32_t arg_num); X509_REQ *php_openssl_csr_from_param( zend_object *csr_obj, zend_string *csr_str, uint32_t arg_num); -#if PHP_OPENSSL_API_VERSION >= 0x10100 && !defined (LIBRESSL_VERSION_NUMBER) +#if !defined (LIBRESSL_VERSION_NUMBER) #define PHP_OPENSSL_ASN1_INTEGER_set ASN1_INTEGER_set_int64 #else #define PHP_OPENSSL_ASN1_INTEGER_set ASN1_INTEGER_set @@ -349,14 +330,12 @@ struct php_openssl_cipher_mode { int aead_ivlen_flag; }; -#if PHP_OPENSSL_API_VERSION >= 0x10100 static inline void php_openssl_set_aead_flags(struct php_openssl_cipher_mode *mode) { mode->is_aead = true; mode->aead_get_tag_flag = EVP_CTRL_AEAD_GET_TAG; mode->aead_set_tag_flag = EVP_CTRL_AEAD_SET_TAG; mode->aead_ivlen_flag = EVP_CTRL_AEAD_SET_IVLEN; } -#endif void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EVP_CIPHER *cipher_type); zend_result php_openssl_validate_iv(const char **piv, size_t *piv_len, size_t iv_required_len, @@ -375,6 +354,4 @@ zend_result php_openssl_cipher_update(const EVP_CIPHER *cipher_type, const EVP_CIPHER *php_openssl_get_evp_cipher_by_name(const char *method); - #endif - diff --git a/ext/openssl/tests/openssl_sign_invalid_algorithm.phpt b/ext/openssl/tests/openssl_sign_invalid_algorithm.phpt new file mode 100644 index 0000000000000..c669a373a1079 --- /dev/null +++ b/ext/openssl/tests/openssl_sign_invalid_algorithm.phpt @@ -0,0 +1,18 @@ +--TEST-- +openssl_sign: invalid algorithm +--EXTENSIONS-- +openssl +--FILE-- + +--EXPECTF-- +Warning: openssl_sign(): Unknown digest algorithm in %s on line %d diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 92168c16175a1..03c18f9be71a2 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -148,10 +148,6 @@ #define HAVE_IPV6_SAN 1 #endif -#if PHP_OPENSSL_API_VERSION < 0x10100 -static RSA *php_openssl_tmp_rsa_cb(SSL *s, int is_export, int keylength); -#endif - extern php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl); extern zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool raw); extern int php_openssl_get_ssl_stream_data_index(void); @@ -987,45 +983,6 @@ static zend_result php_openssl_set_local_cert(SSL_CTX *ctx, php_stream *stream) } /* }}} */ -#if PHP_OPENSSL_API_VERSION < 0x10100 -static int php_openssl_get_crypto_method_ctx_flags(int method_flags) /* {{{ */ -{ - int ssl_ctx_options = SSL_OP_ALL; - -#ifdef SSL_OP_NO_SSLv2 - ssl_ctx_options |= SSL_OP_NO_SSLv2; -#endif -#ifdef HAVE_SSL3 - if (!(method_flags & STREAM_CRYPTO_METHOD_SSLv3)) { - ssl_ctx_options |= SSL_OP_NO_SSLv3; - } -#endif -#ifdef HAVE_TLS1 - if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_0)) { - ssl_ctx_options |= SSL_OP_NO_TLSv1; - } -#endif -#ifdef HAVE_TLS11 - if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_1)) { - ssl_ctx_options |= SSL_OP_NO_TLSv1_1; - } -#endif -#ifdef HAVE_TLS12 - if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_2)) { - ssl_ctx_options |= SSL_OP_NO_TLSv1_2; - } -#endif -#ifdef HAVE_TLS13 - if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_3)) { - ssl_ctx_options |= SSL_OP_NO_TLSv1_3; - } -#endif - - return ssl_ctx_options; -} -/* }}} */ -#endif - static inline int php_openssl_get_min_proto_version_flag(int flags) /* {{{ */ { int ver; @@ -1050,7 +1007,6 @@ static inline int php_openssl_get_max_proto_version_flag(int flags) /* {{{ */ } /* }}} */ -#if PHP_OPENSSL_API_VERSION >= 0x10100 static inline int php_openssl_map_proto_version(int flag) /* {{{ */ { switch (flag) { @@ -1085,7 +1041,6 @@ static int php_openssl_get_max_proto_version(int flags) /* {{{ */ return php_openssl_map_proto_version(php_openssl_get_max_proto_version_flag(flags)); } /* }}} */ -#endif static int php_openssl_get_proto_version_flags(int flags, int min, int max) /* {{{ */ { @@ -1219,30 +1174,6 @@ static void php_openssl_init_server_reneg_limit(php_stream *stream, php_openssl_ } /* }}} */ -#if PHP_OPENSSL_API_VERSION < 0x10100 -static RSA *php_openssl_tmp_rsa_cb(SSL *s, int is_export, int keylength) -{ - BIGNUM *bn = NULL; - static RSA *rsa_tmp = NULL; - - if (!rsa_tmp && ((bn = BN_new()) == NULL)) { - php_error_docref(NULL, E_WARNING, "allocation error generating RSA key"); - } - if (!rsa_tmp && bn) { - if (!BN_set_word(bn, RSA_F4) || ((rsa_tmp = RSA_new()) == NULL) || - !RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL)) { - if (rsa_tmp) { - RSA_free(rsa_tmp); - } - rsa_tmp = NULL; - } - BN_free(bn); - } - - return (rsa_tmp); -} -#endif - static zend_result php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX *ctx) /* {{{ */ { zval *zdhpath = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "dh_param"); @@ -1303,57 +1234,11 @@ static zend_result php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX } /* }}} */ -#if defined(HAVE_ECDH) && PHP_OPENSSL_API_VERSION < 0x10100 -static zend_result php_openssl_set_server_ecdh_curve(php_stream *stream, SSL_CTX *ctx) /* {{{ */ -{ - zval *zvcurve; - int curve_nid; - EC_KEY *ecdh; - - zvcurve = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "ecdh_curve"); - if (zvcurve == NULL) { - SSL_CTX_set_ecdh_auto(ctx, 1); - return SUCCESS; - } else { - if (!try_convert_to_string(zvcurve)) { - return FAILURE; - } - - curve_nid = OBJ_sn2nid(Z_STRVAL_P(zvcurve)); - if (curve_nid == NID_undef) { - php_error_docref(NULL, E_WARNING, "Invalid ecdh_curve specified"); - return FAILURE; - } - } - - ecdh = EC_KEY_new_by_curve_name(curve_nid); - if (ecdh == NULL) { - php_error_docref(NULL, E_WARNING, "Failed generating ECDH curve"); - return FAILURE; - } - - SSL_CTX_set_tmp_ecdh(ctx, ecdh); - EC_KEY_free(ecdh); - - return SUCCESS; -} -/* }}} */ -#endif - static zend_result php_openssl_set_server_specific_opts(php_stream *stream, SSL_CTX *ctx) /* {{{ */ { zval *zv; long ssl_ctx_options = SSL_CTX_get_options(ctx); -#if defined(HAVE_ECDH) && PHP_OPENSSL_API_VERSION < 0x10100 - if (php_openssl_set_server_ecdh_curve(stream, ctx) == FAILURE) { - return FAILURE; - } -#endif - -#if PHP_OPENSSL_API_VERSION < 0x10100 - SSL_CTX_set_tmp_rsa_callback(ctx, php_openssl_tmp_rsa_cb); -#endif /* We now use php_openssl_tmp_rsa_cb to generate a key of appropriate size whenever necessary */ if (php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "rsa_key_size") != NULL) { php_error_docref(NULL, E_WARNING, "rsa_key_size context option has been removed"); @@ -1690,11 +1575,7 @@ static zend_result php_openssl_setup_crypto(php_stream *stream, GET_VER_OPT_LONG("min_proto_version", min_version); GET_VER_OPT_LONG("max_proto_version", max_version); method_flags = php_openssl_get_proto_version_flags(method_flags, min_version, max_version); -#if PHP_OPENSSL_API_VERSION < 0x10100 - ssl_ctx_options = php_openssl_get_crypto_method_ctx_flags(method_flags); -#else ssl_ctx_options = SSL_OP_ALL; -#endif if (GET_VER_OPT("no_ticket") && zend_is_true(val)) { ssl_ctx_options |= SSL_OP_NO_TICKET; @@ -1780,10 +1661,8 @@ static zend_result php_openssl_setup_crypto(php_stream *stream, SSL_CTX_set_options(sslsock->ctx, ssl_ctx_options); -#if PHP_OPENSSL_API_VERSION >= 0x10100 SSL_CTX_set_min_proto_version(sslsock->ctx, php_openssl_get_min_proto_version(method_flags)); SSL_CTX_set_max_proto_version(sslsock->ctx, php_openssl_get_max_proto_version(method_flags)); -#endif if (sslsock->is_client == 0 && PHP_STREAM_CONTEXT(stream) && diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 8db1d10c698c8..2189f94c992f5 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -956,6 +956,7 @@ PHP_FUNCTION(pcntl_sigprocmask) RETURN_THROWS(); } + zend_hash_real_init_packed(Z_ARRVAL_P(user_old_set)); for (unsigned int signal_no = 1; signal_no < PCNTL_G(num_signals); ++signal_no) { if (sigismember(&old_set, signal_no) != 1) { continue; @@ -1680,6 +1681,7 @@ PHP_FUNCTION(pcntl_getcpuaffinity) zend_ulong maxcpus = (zend_ulong)sysconf(_SC_NPROCESSORS_CONF); array_init(return_value); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for (zend_ulong i = 0; i < maxcpus; i ++) { if (PCNTL_CPU_ISSET(i, mask)) { diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index a2a577a6745a0..8e0fb2cce5f9b 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -199,13 +199,6 @@ static void php_pcre_efree(void *block, void *data) efree(block); } -#ifdef PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK - /* pcre 10.38 needs PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK, disabled by default */ -#define PHP_PCRE_DEFAULT_EXTRA_COPTIONS PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK -#else -#define PHP_PCRE_DEFAULT_EXTRA_COPTIONS 0 -#endif - #define PHP_PCRE_PREALLOC_MDATA_SIZE 32 static void php_pcre_init_pcre2(uint8_t jit) @@ -226,8 +219,6 @@ static void php_pcre_init_pcre2(uint8_t jit) } } - pcre2_set_compile_extra_options(cctx, PHP_PCRE_DEFAULT_EXTRA_COPTIONS); - if (!mctx) { mctx = pcre2_match_context_create(gctx); if (!mctx) { @@ -590,7 +581,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo #else uint32_t coptions = 0; #endif - uint32_t eoptions = PHP_PCRE_DEFAULT_EXTRA_COPTIONS; + uint32_t eoptions = 0; PCRE2_UCHAR error[128]; PCRE2_SIZE erroffset; int errnumber; diff --git a/ext/pcre/tests/bug70345.phpt b/ext/pcre/tests/bug70345.phpt index 42d4f8b12e265..bdfa2041fc08a 100644 --- a/ext/pcre/tests/bug70345.phpt +++ b/ext/pcre/tests/bug70345.phpt @@ -1,5 +1,10 @@ --TEST-- Bug #70345 (Multiple vulnerabilities related to PCRE functions) +--SKIPIF-- + --EXPECTF-- +Warning: preg_split(): Compilation failed: \K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) at offset 9 in %s on line %d bool(false) -Warning: preg_match(): Get subpatterns list failed in %s on line %d -array(0) { -} +Warning: preg_match(): Compilation failed: \K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) at offset 12 in %s on line %d +NULL diff --git a/ext/pcre/tests/bug70345_old.phpt b/ext/pcre/tests/bug70345_old.phpt new file mode 100644 index 0000000000000..ea455a59330d4 --- /dev/null +++ b/ext/pcre/tests/bug70345_old.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug #70345 (Multiple vulnerabilities related to PCRE functions) +--SKIPIF-- += 38) { + die("skip new pcre version"); +} +--FILE-- + +--EXPECTF-- +bool(false) + +Warning: preg_match(): Get subpatterns list failed in %s on line %d +array(0) { +} diff --git a/ext/pcre/tests/bug75457.phpt b/ext/pcre/tests/bug75457.phpt index 87dc12a1ad056..1401b25ff6fb7 100644 --- a/ext/pcre/tests/bug75457.phpt +++ b/ext/pcre/tests/bug75457.phpt @@ -6,5 +6,5 @@ $pattern = "/(((?(?C)0?=))(?!()0|.(?0)0)())/"; var_dump(preg_match($pattern, "hello")); ?> --EXPECTF-- -Warning: preg_match(): Compilation failed: %r(atomic|)%r assertion expected after (?( or (?(?C) at offset 8 in %sbug75457.php on line %d +Warning: preg_match(): Compilation failed:%r( atomic|)%r assertion expected after (?( or (?(?C) at offset 8 in %sbug75457.php on line %d bool(false) diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 0ffded87c08a0..afd6b2a43da6a 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -212,6 +212,7 @@ static void pdo_get_lazy_object(pdo_stmt_t *stmt, zval *return_value) /* {{{ */ pdo_row_t *row = zend_object_alloc(sizeof(pdo_row_t), pdo_row_ce); row->stmt = stmt; zend_object_std_init(&row->std, pdo_row_ce); + object_properties_init(&row->std, pdo_row_ce); stmt->lazy_object_ref = &row->std; GC_ADDREF(&stmt->std); GC_DELREF(&row->std); @@ -2386,9 +2387,10 @@ static zval *pdo_row_get_property_ptr_ptr(zend_object *object, zend_string *name ZEND_IGNORE_VALUE(object); ZEND_IGNORE_VALUE(name); ZEND_IGNORE_VALUE(type); - ZEND_IGNORE_VALUE(cache_slot); - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } return NULL; } @@ -2399,12 +2401,14 @@ static void pdo_row_free_storage(zend_object *std) row->stmt->lazy_object_ref = NULL; OBJ_RELEASE(&row->stmt->std); } + zend_object_std_dtor(std); } static zend_object *pdo_row_new(zend_class_entry *ce) { pdo_row_t *row = zend_object_alloc(sizeof(pdo_row_t), ce); zend_object_std_init(&row->std, ce); + object_properties_init(&row->std, ce); return &row->std; } diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index 0666057b66b6e..f6d5b1144f382 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -594,18 +594,19 @@ static void firebird_handle_closer(pdo_dbh_t *dbh) /* {{{ */ } H->in_manually_txn = 0; - if (isc_detach_database(H->isc_status, &H->db)) { + /* isc_detach_database returns 0 on success, 1 on failure. */ + if (H->db && isc_detach_database(H->isc_status, &H->db)) { php_firebird_error(dbh); } if (H->date_format) { - zend_string_release_ex(H->date_format, false); + pefree(H->date_format, dbh->is_persistent); } if (H->time_format) { - zend_string_release_ex(H->time_format, false); + pefree(H->time_format, dbh->is_persistent); } if (H->timestamp_format) { - zend_string_release_ex(H->timestamp_format, false); + pefree(H->timestamp_format, dbh->is_persistent); } if (H->einfo.errmsg) { @@ -684,7 +685,7 @@ static bool firebird_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, /* {{{ */ /* make all parameters nullable */ unsigned int i; - XSQLVAR* var; + XSQLVAR* var; for (i = 0, var = S->in_sqlda->sqlvar; i < S->in_sqlda->sqld; i++, var++) { /* The low bit of sqltype indicates that the parameter can take a NULL value */ var->sqltype |= 1; @@ -1091,9 +1092,11 @@ static bool pdo_firebird_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val return false; } if (H->date_format) { - zend_string_release_ex(H->date_format, false); + pefree(H->date_format, dbh->is_persistent); + H->date_format = NULL; } - H->date_format = str; + H->date_format = pestrndup(ZSTR_VAL(str), ZSTR_LEN(str),dbh->is_persistent); + zend_string_release_ex(str, 0); } return true; @@ -1104,9 +1107,11 @@ static bool pdo_firebird_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val return false; } if (H->time_format) { - zend_string_release_ex(H->time_format, false); + pefree(H->time_format, dbh->is_persistent); + H->time_format = NULL; } - H->time_format = str; + H->time_format = pestrndup(ZSTR_VAL(str), ZSTR_LEN(str),dbh->is_persistent); + zend_string_release_ex(str, 0); } return true; @@ -1117,9 +1122,11 @@ static bool pdo_firebird_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val return false; } if (H->timestamp_format) { - zend_string_release_ex(H->timestamp_format, false); + pefree(H->timestamp_format, dbh->is_persistent); + H->timestamp_format = NULL; } - H->timestamp_format = str; + H->timestamp_format = pestrndup(ZSTR_VAL(str), ZSTR_LEN(str),dbh->is_persistent); + zend_string_release_ex(str, 0); } return true; @@ -1240,27 +1247,15 @@ static int pdo_firebird_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val) return 1; case PDO_FB_ATTR_DATE_FORMAT: - if (H->date_format) { - ZVAL_STR_COPY(val, H->date_format); - } else { - ZVAL_STRING(val, PDO_FB_DEF_DATE_FMT); - } + ZVAL_STRING(val, H->date_format ? H->date_format : PDO_FB_DEF_DATE_FMT); return 1; case PDO_FB_ATTR_TIME_FORMAT: - if (H->time_format) { - ZVAL_STR_COPY(val, H->time_format); - } else { - ZVAL_STRING(val, PDO_FB_DEF_TIME_FMT); - } + ZVAL_STRING(val, H->time_format ? H->time_format : PDO_FB_DEF_TIME_FMT); return 1; case PDO_FB_ATTR_TIMESTAMP_FORMAT: - if (H->timestamp_format) { - ZVAL_STR_COPY(val, H->timestamp_format); - } else { - ZVAL_STRING(val, PDO_FB_DEF_TIMESTAMP_FMT); - } + ZVAL_STRING(val, H->timestamp_format ? H->timestamp_format : PDO_FB_DEF_TIMESTAMP_FMT); return 1; case PDO_FB_TRANSACTION_ISOLATION_LEVEL: @@ -1422,7 +1417,7 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* "HY000", H->isc_status[1], errmsg); } - if (dbh->auto_commit && !H->tr) { + if (ret && dbh->auto_commit && !H->tr) { ret = php_firebird_begin_transaction(dbh, /* auto commit mode */ true); } diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c index 4310269314ce0..60a5e60e11bde 100644 --- a/ext/pdo_firebird/firebird_statement.c +++ b/ext/pdo_firebird/firebird_statement.c @@ -93,7 +93,7 @@ static int get_formatted_time_tz(pdo_stmt_t *stmt, const ISC_TIME_TZ* timeTz, zv } time = fb_encode_time(hours, minutes, seconds, fractions); isc_decode_sql_time(&time, &t); - fmt = S->H->time_format ? ZSTR_VAL(S->H->time_format) : PDO_FB_DEF_TIME_FMT; + fmt = S->H->time_format ? S->H->time_format : PDO_FB_DEF_TIME_FMT; size_t len = strftime(timeBuf, sizeof(timeBuf), fmt, &t); if (len == 0) { @@ -123,7 +123,7 @@ static int get_formatted_timestamp_tz(pdo_stmt_t *stmt, const ISC_TIMESTAMP_TZ* ts.timestamp_time = fb_encode_time(hours, minutes, seconds, fractions); isc_decode_timestamp(&ts, &t); - fmt = S->H->timestamp_format ? ZSTR_VAL(S->H->timestamp_format) : PDO_FB_DEF_TIMESTAMP_FMT; + fmt = S->H->timestamp_format ? S->H->timestamp_format : PDO_FB_DEF_TIMESTAMP_FMT; size_t len = strftime(timestampBuf, sizeof(timestampBuf), fmt, &t); if (len == 0) { @@ -546,18 +546,18 @@ static int pdo_firebird_stmt_get_col( break; case SQL_TYPE_DATE: isc_decode_sql_date((ISC_DATE*)var->sqldata, &t); - fmt = S->H->date_format ? ZSTR_VAL(S->H->date_format) : PDO_FB_DEF_DATE_FMT; + fmt = S->H->date_format ? S->H->date_format : PDO_FB_DEF_DATE_FMT; if (0) { case SQL_TYPE_TIME: isc_decode_sql_time((ISC_TIME*)var->sqldata, &t); - fmt = S->H->time_format ? ZSTR_VAL(S->H->time_format) : PDO_FB_DEF_TIME_FMT; + fmt = S->H->time_format ? S->H->time_format : PDO_FB_DEF_TIME_FMT; } else if (0) { case SQL_TIMESTAMP: { ISC_TIMESTAMP timestamp = php_get_isc_timestamp_from_sqldata(var->sqldata); isc_decode_timestamp(×tamp, &t); } - fmt = S->H->timestamp_format ? ZSTR_VAL(S->H->timestamp_format) : PDO_FB_DEF_TIMESTAMP_FMT; + fmt = S->H->timestamp_format ? S->H->timestamp_format : PDO_FB_DEF_TIMESTAMP_FMT; } /* convert the timestamp into a string */ char buf[80]; diff --git a/ext/pdo_firebird/php_pdo_firebird_int.h b/ext/pdo_firebird/php_pdo_firebird_int.h index 1d58be1c4b717..a62c152ffab3e 100644 --- a/ext/pdo_firebird/php_pdo_firebird_int.h +++ b/ext/pdo_firebird/php_pdo_firebird_int.h @@ -73,9 +73,9 @@ typedef struct { zend_ulong txn_isolation_level; /* date and time format strings, can be set by the set_attribute method */ - zend_string *date_format; - zend_string *time_format; - zend_string *timestamp_format; + char *date_format; + char *time_format; + char *timestamp_format; unsigned sql_dialect:2; diff --git a/ext/pdo_firebird/tests/gh17383.phpt b/ext/pdo_firebird/tests/gh17383.phpt new file mode 100644 index 0000000000000..6adad311938c6 --- /dev/null +++ b/ext/pdo_firebird/tests/gh17383.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-17383 (PDOException has wrong code and message since PHP 8.4) +--EXTENSIONS-- +pdo_firebird +--SKIPIF-- + +--XLEAK-- +A bug in firebird causes a memory leak when calling `isc_attach_database()`. +See https://github.com/FirebirdSQL/firebird/issues/7849 +--FILE-- +getCode() . "\n"; + echo 'PDOException message: ' . $e->getMessage() . "\n"; + echo "\n"; + } +} +?> +--EXPECT-- +PDOException code: 335544721 +PDOException message: SQLSTATE[HY000] [335544721] Unable to complete network request to host "invalid_host". + +PDOException code: 335544472 +PDOException message: SQLSTATE[HY000] [335544472] Your user name and password are not defined. Ask your database administrator to set up a Firebird login. + +PDOException code: 335544472 +PDOException message: SQLSTATE[HY000] [335544472] Your user name and password are not defined. Ask your database administrator to set up a Firebird login. diff --git a/ext/pdo_firebird/tests/gh18276.phpt b/ext/pdo_firebird/tests/gh18276.phpt new file mode 100644 index 0000000000000..610876166ccf7 --- /dev/null +++ b/ext/pdo_firebird/tests/gh18276.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-18276 (persistent connection - setAttribute(Pdo\Firebird::ATTR_DATE_FORMAT, ..) results in "zend_mm_heap corrupted") +--EXTENSIONS-- +pdo_firebird +--SKIPIF-- + +--XLEAK-- +A bug in firebird causes a memory leak when calling `isc_attach_database()`. +See https://github.com/FirebirdSQL/firebird/issues/7849 +--FILE-- + true, + ], + ); + // Avoid interned + $dbh->setAttribute(PDO::FB_ATTR_DATE_FORMAT, str_repeat('Y----m----d', random_int(1, 1))); + $dbh->setAttribute(PDO::FB_ATTR_TIME_FORMAT, str_repeat('H::::i::::s', random_int(1, 1))); + $dbh->setAttribute(PDO::FB_ATTR_TIMESTAMP_FORMAT, str_repeat('Y----m----d....H::::i::::s', random_int(1, 1))); + unset($dbh); +} + +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index dd3b9535a1626..4895463db4b08 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -619,27 +619,29 @@ static bool pgsql_handle_rollback(pdo_dbh_t *dbh) static bool _pdo_pgsql_send_copy_data(pdo_pgsql_db_handle *H, zval *line) { size_t query_len; - char *query; + zend_string *query; if (!try_convert_to_string(line)) { return false; } query_len = Z_STRLEN_P(line); - query = emalloc(query_len + 2); /* room for \n\0 */ - memcpy(query, Z_STRVAL_P(line), query_len); + query = zend_string_alloc(query_len + 2, false); /* room for \n\0 */ + memcpy(ZSTR_VAL(query), Z_STRVAL_P(line), query_len + 1); + ZSTR_LEN(query) = query_len; - if (query[query_len - 1] != '\n') { - query[query_len++] = '\n'; + if (query_len > 0 && ZSTR_VAL(query)[query_len - 1] != '\n') { + ZSTR_VAL(query)[query_len] = '\n'; + ZSTR_VAL(query)[query_len + 1] = '\0'; + ZSTR_LEN(query) ++; } - query[query_len] = '\0'; - if (PQputCopyData(H->server, query, query_len) != 1) { - efree(query); + if (PQputCopyData(H->server, ZSTR_VAL(query), ZSTR_LEN(query)) != 1) { + zend_string_release_ex(query, false); return false; } - efree(query); + zend_string_release_ex(query, false); return true; } diff --git a/ext/pdo_sqlite/pdo_sqlite.c b/ext/pdo_sqlite/pdo_sqlite.c index bc47c15a1eb5e..7661b36c5d314 100644 --- a/ext/pdo_sqlite/pdo_sqlite.c +++ b/ext/pdo_sqlite/pdo_sqlite.c @@ -332,6 +332,36 @@ PHP_METHOD(Pdo_Sqlite, openBlob) } } +PHP_METHOD(Pdo_Sqlite, setAuthorizer) +{ + zend_fcall_info fci; + zend_fcall_info_cache fcc; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_FUNC_NO_TRAMPOLINE_FREE_OR_NULL(fci, fcc) + ZEND_PARSE_PARAMETERS_END(); + + pdo_dbh_t *dbh = Z_PDO_DBH_P(ZEND_THIS); + PDO_CONSTRUCT_CHECK_WITH_CLEANUP(free_fcc); + pdo_sqlite_db_handle *db_handle = (pdo_sqlite_db_handle *) dbh->driver_data; + + /* Clear previously set callback */ + if (ZEND_FCC_INITIALIZED(db_handle->authorizer_fcc)) { + zend_fcc_dtor(&db_handle->authorizer_fcc); + } + + /* Only enable userland authorizer if argument is not NULL */ + if (ZEND_FCI_INITIALIZED(fci)) { + zend_fcc_dup(&db_handle->authorizer_fcc, &fcc); + } + + return; + +free_fcc: + zend_release_fcall_info_cache(&fcc); + RETURN_THROWS(); +} + static int php_sqlite_collation_callback(void *context, int string1_len, const void *string1, int string2_len, const void *string2) { @@ -349,9 +379,10 @@ static int php_sqlite_collation_callback(void *context, int string1_len, const v if (!Z_ISUNDEF(retval)) { if (Z_TYPE(retval) != IS_LONG) { zend_string *func_name = get_active_function_or_method_name(); - zend_type_error("%s(): Return value of the callback must be of type int, %s returned", + zend_type_error("%s(): Return value of the collation callback must be of type int, %s returned", ZSTR_VAL(func_name), zend_zval_value_name(&retval)); zend_string_release(func_name); + zval_ptr_dtor(&retval); return FAILURE; } if (Z_LVAL(retval) > 0) { @@ -359,7 +390,6 @@ static int php_sqlite_collation_callback(void *context, int string1_len, const v } else if (Z_LVAL(retval) < 0) { ret = -1; } - zval_ptr_dtor(&retval); } zval_ptr_dtor(&zargs[0]); diff --git a/ext/pdo_sqlite/pdo_sqlite.stub.php b/ext/pdo_sqlite/pdo_sqlite.stub.php index e22c8ce10fccc..3832683598ed5 100644 --- a/ext/pdo_sqlite/pdo_sqlite.stub.php +++ b/ext/pdo_sqlite/pdo_sqlite.stub.php @@ -33,6 +33,16 @@ class Sqlite extends \PDO /** @cvalue PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES */ public const int ATTR_EXTENDED_RESULT_CODES = UNKNOWN; + /** @cvalue SQLITE_OK */ + public const int OK = UNKNOWN; + + /* Constants for authorizer return */ + + /** @cvalue SQLITE_DENY */ + public const int DENY = UNKNOWN; + /** @cvalue SQLITE_IGNORE */ + public const int IGNORE = UNKNOWN; + // Registers an aggregating User Defined Function for use in SQL statements public function createAggregate( string $name, @@ -63,4 +73,6 @@ public function openBlob( ?string $dbname = "main", int $flags = \Pdo\Sqlite::OPEN_READONLY ) {} + + public function setAuthorizer(?callable $callback): void {} } diff --git a/ext/pdo_sqlite/pdo_sqlite_arginfo.h b/ext/pdo_sqlite/pdo_sqlite_arginfo.h index 4abbc0bb625c6..75de256e55c7b 100644 --- a/ext/pdo_sqlite/pdo_sqlite_arginfo.h +++ b/ext/pdo_sqlite/pdo_sqlite_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 7ceaf5fc8e9c92bf192e824084a706794395ce1a */ + * Stub hash: f8cd6b3c6aa662d76dca3d0a28d61acfb5a611b5 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Pdo_Sqlite_createAggregate, 0, 3, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) @@ -34,6 +34,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Pdo_Sqlite_openBlob, 0, 0, 3) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Pdo\\Sqlite::OPEN_READONLY") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Pdo_Sqlite_setAuthorizer, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 1) +ZEND_END_ARG_INFO() + ZEND_METHOD(Pdo_Sqlite, createAggregate); ZEND_METHOD(Pdo_Sqlite, createCollation); ZEND_METHOD(Pdo_Sqlite, createFunction); @@ -41,6 +45,7 @@ ZEND_METHOD(Pdo_Sqlite, createFunction); ZEND_METHOD(Pdo_Sqlite, loadExtension); #endif ZEND_METHOD(Pdo_Sqlite, openBlob); +ZEND_METHOD(Pdo_Sqlite, setAuthorizer); static const zend_function_entry class_Pdo_Sqlite_methods[] = { ZEND_ME(Pdo_Sqlite, createAggregate, arginfo_class_Pdo_Sqlite_createAggregate, ZEND_ACC_PUBLIC) @@ -50,6 +55,7 @@ static const zend_function_entry class_Pdo_Sqlite_methods[] = { ZEND_ME(Pdo_Sqlite, loadExtension, arginfo_class_Pdo_Sqlite_loadExtension, ZEND_ACC_PUBLIC) #endif ZEND_ME(Pdo_Sqlite, openBlob, arginfo_class_Pdo_Sqlite_openBlob, ZEND_ACC_PUBLIC) + ZEND_ME(Pdo_Sqlite, setAuthorizer, arginfo_class_Pdo_Sqlite_setAuthorizer, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -104,5 +110,23 @@ static zend_class_entry *register_class_Pdo_Sqlite(zend_class_entry *class_entry zend_declare_typed_class_constant(class_entry, const_ATTR_EXTENDED_RESULT_CODES_name, &const_ATTR_EXTENDED_RESULT_CODES_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_ATTR_EXTENDED_RESULT_CODES_name); + zval const_OK_value; + ZVAL_LONG(&const_OK_value, SQLITE_OK); + zend_string *const_OK_name = zend_string_init_interned("OK", sizeof("OK") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_OK_name, &const_OK_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_OK_name); + + zval const_DENY_value; + ZVAL_LONG(&const_DENY_value, SQLITE_DENY); + zend_string *const_DENY_name = zend_string_init_interned("DENY", sizeof("DENY") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_DENY_name, &const_DENY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_DENY_name); + + zval const_IGNORE_value; + ZVAL_LONG(&const_IGNORE_value, SQLITE_IGNORE); + zend_string *const_IGNORE_name = zend_string_init_interned("IGNORE", sizeof("IGNORE") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_IGNORE_name, &const_IGNORE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_IGNORE_name); + return class_entry; } diff --git a/ext/pdo_sqlite/php_pdo_sqlite_int.h b/ext/pdo_sqlite/php_pdo_sqlite_int.h index 08d5f877ad520..4a39781f85c96 100644 --- a/ext/pdo_sqlite/php_pdo_sqlite_int.h +++ b/ext/pdo_sqlite/php_pdo_sqlite_int.h @@ -50,6 +50,7 @@ typedef struct { pdo_sqlite_error_info einfo; struct pdo_sqlite_func *funcs; struct pdo_sqlite_collation *collations; + zend_fcall_info_cache authorizer_fcc; } pdo_sqlite_db_handle; typedef struct { diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index 645d7bc3333ed..ddf25d4965f06 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -97,6 +97,10 @@ static void pdo_sqlite_cleanup_callbacks(pdo_sqlite_db_handle *H) { struct pdo_sqlite_func *func; + if (ZEND_FCC_INITIALIZED(H->authorizer_fcc)) { + zend_fcc_dtor(&H->authorizer_fcc); + } + while (H->funcs) { func = H->funcs; H->funcs = func->next; @@ -226,6 +230,19 @@ static zend_string* sqlite_handle_quoter(pdo_dbh_t *dbh, const zend_string *unqu if (ZSTR_LEN(unquoted) > (INT_MAX - 3) / 2) { return NULL; } + + if (UNEXPECTED(zend_str_has_nul_byte(unquoted))) { + if (dbh->error_mode == PDO_ERRMODE_EXCEPTION) { + zend_throw_exception_ex( + php_pdo_get_exception(), 0, + "SQLite PDO::quote does not support null bytes"); + } else if (dbh->error_mode == PDO_ERRMODE_WARNING) { + php_error_docref(NULL, E_WARNING, + "SQLite PDO::quote does not support null bytes"); + } + return NULL; + } + quoted = safe_emalloc(2, ZSTR_LEN(unquoted), 3); /* TODO use %Q format? */ sqlite3_snprintf(2*ZSTR_LEN(unquoted) + 3, quoted, "'%q'", ZSTR_VAL(unquoted)); @@ -701,6 +718,10 @@ static void pdo_sqlite_get_gc(pdo_dbh_t *dbh, zend_get_gc_buffer *gc_buffer) { pdo_sqlite_db_handle *H = dbh->driver_data; + if (ZEND_FCC_INITIALIZED(H->authorizer_fcc)) { + zend_get_gc_buffer_add_fcc(gc_buffer, &H->authorizer_fcc); + } + struct pdo_sqlite_func *func = H->funcs; while (func) { if (ZEND_FCC_INITIALIZED(func->func)) { @@ -741,7 +762,7 @@ static const struct pdo_dbh_methods sqlite_methods = { pdo_sqlite_request_shutdown, pdo_sqlite_in_transaction, pdo_sqlite_get_gc, - pdo_sqlite_scanner + pdo_sqlite_scanner }; static char *make_filename_safe(const char *filename) @@ -771,24 +792,77 @@ static char *make_filename_safe(const char *filename) return estrdup(filename); } -static int authorizer(void *autharg, int access_type, const char *arg3, const char *arg4, - const char *arg5, const char *arg6) +#define ZVAL_NULLABLE_STRING(zv, str) do { \ + zval *zv_ = zv; \ + const char *str_ = str; \ + if (str_) { \ + ZVAL_STRING(zv_, str_); \ + } else { \ + ZVAL_NULL(zv_); \ + } \ +} while (0) + +static int authorizer(void *autharg, int access_type, const char *arg1, const char *arg2, + const char *arg3, const char *arg4) { - char *filename; - switch (access_type) { - case SQLITE_ATTACH: { - filename = make_filename_safe(arg3); + if (PG(open_basedir) && *PG(open_basedir)) { + if (access_type == SQLITE_ATTACH) { + char *filename = make_filename_safe(arg1); if (!filename) { return SQLITE_DENY; } efree(filename); - return SQLITE_OK; } + } - default: - /* access allowed */ - return SQLITE_OK; + pdo_sqlite_db_handle *db_obj = autharg; + + /* fallback to access allowed if authorizer callback is not defined */ + if (!ZEND_FCC_INITIALIZED(db_obj->authorizer_fcc)) { + return SQLITE_OK; } + + /* call userland authorizer callback, if set */ + zval retval; + zval argv[5]; + + ZVAL_LONG(&argv[0], access_type); + ZVAL_NULLABLE_STRING(&argv[1], arg1); + ZVAL_NULLABLE_STRING(&argv[2], arg2); + ZVAL_NULLABLE_STRING(&argv[3], arg3); + ZVAL_NULLABLE_STRING(&argv[4], arg4); + + int authreturn = SQLITE_DENY; + + zend_call_known_fcc(&db_obj->authorizer_fcc, &retval, /* argc */ 5, argv, /* named_params */ NULL); + if (Z_ISUNDEF(retval)) { + ZEND_ASSERT(EG(exception)); + } else { + if (Z_TYPE(retval) != IS_LONG) { + zend_string *func_name = get_active_function_or_method_name(); + zend_type_error("%s(): Return value of the authorizer callback must be of type int, %s returned", + ZSTR_VAL(func_name), zend_zval_value_name(&retval)); + zend_string_release(func_name); + } else { + authreturn = Z_LVAL(retval); + + if (authreturn != SQLITE_OK && authreturn != SQLITE_IGNORE && authreturn != SQLITE_DENY) { + zend_string *func_name = get_active_function_or_method_name(); + zend_value_error("%s(): Return value of the authorizer callback must be one of Pdo\\Sqlite::OK, Pdo\\Sqlite::DENY, or Pdo\\Sqlite::IGNORE", + ZSTR_VAL(func_name)); + zend_string_release(func_name); + authreturn = SQLITE_DENY; + } + } + } + + zval_ptr_dtor(&retval); + zval_ptr_dtor(&argv[1]); + zval_ptr_dtor(&argv[2]); + zval_ptr_dtor(&argv[3]); + zval_ptr_dtor(&argv[4]); + + return authreturn; } static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ */ @@ -830,9 +904,7 @@ static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{ goto cleanup; } - if (PG(open_basedir) && *PG(open_basedir)) { - sqlite3_set_authorizer(H->db, authorizer, NULL); - } + sqlite3_set_authorizer(H->db, authorizer, H); if (driver_options) { timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, timeout); diff --git a/ext/pdo_sqlite/tests/gh13952.phpt b/ext/pdo_sqlite/tests/gh13952.phpt new file mode 100644 index 0000000000000..b6a080cfa22a2 --- /dev/null +++ b/ext/pdo_sqlite/tests/gh13952.phpt @@ -0,0 +1,79 @@ +--TEST-- +GH-13952 (sqlite PDO::quote handles null bytes correctly) +--EXTENSIONS-- +pdo +pdo_sqlite +--FILE-- + PDO::ERRMODE_EXCEPTION, + 'warning' => PDO::ERRMODE_WARNING, + 'silent' => PDO::ERRMODE_SILENT, +]; + +$test_cases = [ + "", + "x", + "\x00", + "a\x00b", + "\x00\x00\x00", + "foobar", + "foo'''bar", + "'foo'''bar'", + "foo\x00bar", + "'foo'\x00'bar'", + "foo\x00\x00\x00bar", + "\x00foo\x00\x00\x00bar\x00", + "\x00\x00\x00foo", + "foo\x00\x00\x00", + "\x80", // << invalid UTF-8 + "\x00\x80\x00", // << invalid UTF-8 with null bytes +]; + +foreach ($modes as $mode_name => $mode) { + echo "Testing error mode: $mode_name\n"; + $db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => $mode]); + + foreach ($test_cases as $test) { + $contains_null = str_contains($test, "\x00"); + + if ($mode === PDO::ERRMODE_EXCEPTION && $contains_null) { + set_error_handler(fn() => throw new PDOException(), E_WARNING); + try { + $db->quote($test); + throw new LogicException("Expected exception not thrown."); + } catch (PDOException) { + // expected + } finally { + restore_error_handler(); + } + } else { + set_error_handler(fn() => null, E_WARNING); + $quoted = $db->quote($test); + restore_error_handler(); + + if ($contains_null) { + if ($quoted !== false) { + throw new LogicException("Expected false, got: " . var_export($quoted, true)); + } + } else { + if ($quoted === false) { + throw new LogicException("Unexpected false from quote()."); + } + $fetched = $db->query("SELECT $quoted")->fetchColumn(); + if ($fetched !== $test) { + throw new LogicException("Data corrupted: expected " . var_export($test, true) . " got " . var_export($fetched, true)); + } + } + } + } +} + +echo "ok\n"; +?> +--EXPECT-- +Testing error mode: exception +Testing error mode: warning +Testing error mode: silent +ok diff --git a/ext/pdo_sqlite/tests/gh18114.phpt b/ext/pdo_sqlite/tests/gh18114.phpt new file mode 100644 index 0000000000000..850558845485a --- /dev/null +++ b/ext/pdo_sqlite/tests/gh18114.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-18114 (pdo lazy object crash) +--EXTENSIONS-- +pdo_sqlite +--FILE-- +query('select 1 as queryString'); +$data = $x->fetch(PDO::FETCH_LAZY); +foreach ($data as $entry) { + var_dump($entry); +} +var_dump((array) $data); +echo "Done\n"; +?> +--EXPECT-- +array(0) { +} +Done diff --git a/ext/pdo_sqlite/tests/subclasses/pdosqlite_setauthorizer.phpt b/ext/pdo_sqlite/tests/subclasses/pdosqlite_setauthorizer.phpt new file mode 100644 index 0000000000000..d1e9039ea1c4d --- /dev/null +++ b/ext/pdo_sqlite/tests/subclasses/pdosqlite_setauthorizer.phpt @@ -0,0 +1,101 @@ +--TEST-- +Pdo\Sqlite user authorizer callback +--EXTENSIONS-- +pdo_sqlite +--FILE-- +setAuthorizer(function (int $action) { + if ($action == 21 /* SELECT */) { + return Pdo\Sqlite::OK; + } + + return Pdo\Sqlite::DENY; +}); + +// This query should be accepted +var_dump($db->query('SELECT 1;')); + +try { + // This one should fail + var_dump($db->exec('CREATE TABLE test (a, b);')); +} catch (\Exception $e) { + echo $e->getMessage() . "\n"; +} + +// Test disabling the authorizer +$db->setAuthorizer(null); + +// This should now succeed +var_dump($db->exec('CREATE TABLE test (a); INSERT INTO test VALUES (42);')); +var_dump($db->exec('SELECT a FROM test;')); + +// Test if we are getting the correct arguments +$db->setAuthorizer(function (int $action) { + $constants = ["COPY", "CREATE_INDEX", "CREATE_TABLE", "CREATE_TEMP_INDEX", "CREATE_TEMP_TABLE", "CREATE_TEMP_TRIGGER", "CREATE_TEMP_VIEW", "CREATE_TRIGGER", "CREATE_VIEW", "DELETE", "DROP_INDEX", "DROP_TABLE", "DROP_TEMP_INDEX", "DROP_TEMP_TABLE", "DROP_TEMP_TRIGGER", "DROP_TEMP_VIEW", "DROP_TRIGGER", "DROP_VIEW", "INSERT", "PRAGMA", "READ", "SELECT", "TRANSACTION", "UPDATE"]; + + var_dump($constants[$action], implode(',', array_slice(func_get_args(), 1))); + return Pdo\Sqlite::OK; +}); + +var_dump($db->exec('SELECT * FROM test WHERE a = 42;')); +var_dump($db->exec('DROP TABLE test;')); + +// Try to return something invalid from the authorizer +$db->setAuthorizer(function () { + return 'FAIL'; +}); + +try { + var_dump($db->query('SELECT 1;')); +} catch (\Error $e) { + echo $e->getMessage() . "\n"; +} + +$db->setAuthorizer(function () { + return 4200; +}); + +try { + var_dump($db->query('SELECT 1;')); +} catch (\Error $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECTF-- +object(PDOStatement)#%d (1) { + ["queryString"]=> + string(9) "SELECT 1;" +} +SQLSTATE[HY000]: General error: 23 not authorized +int(1) +int(1) +string(6) "SELECT" +string(3) ",,," +string(4) "READ" +string(12) "test,a,main," +string(4) "READ" +string(12) "test,a,main," +int(1) +string(6) "DELETE" +string(20) "sqlite_master,,main," +string(10) "DROP_TABLE" +string(11) "test,,main," +string(6) "DELETE" +string(11) "test,,main," +string(6) "DELETE" +string(20) "sqlite_master,,main," +string(4) "READ" +string(28) "sqlite_master,tbl_name,main," +string(4) "READ" +string(24) "sqlite_master,type,main," +string(6) "UPDATE" +string(28) "sqlite_master,rootpage,main," +string(4) "READ" +string(28) "sqlite_master,rootpage,main," +int(1) +PDO::query(): Return value of the authorizer callback must be of type int, string returned +PDO::query(): Return value of the authorizer callback must be one of Pdo\Sqlite::OK, Pdo\Sqlite::DENY, or Pdo\Sqlite::IGNORE diff --git a/ext/pdo_sqlite/tests/subclasses/pdosqlite_setauthorizer_trampoline.phpt b/ext/pdo_sqlite/tests/subclasses/pdosqlite_setauthorizer_trampoline.phpt new file mode 100644 index 0000000000000..c93a1f2e34a51 --- /dev/null +++ b/ext/pdo_sqlite/tests/subclasses/pdosqlite_setauthorizer_trampoline.phpt @@ -0,0 +1,43 @@ +--TEST-- +Pdo\Sqlite user authorizer trampoline callback +--EXTENSIONS-- +pdo_sqlite +--FILE-- +setAuthorizer($callback); + +// This query should be accepted +var_dump($db->query('SELECT 1;')); + +try { + // This one should fail + var_dump($db->query('CREATE TABLE test (a, b);')); +} catch (\Exception $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECTF-- +Trampoline for authorizer +object(PDOStatement)#%d (1) { + ["queryString"]=> + string(9) "SELECT 1;" +} +Trampoline for authorizer +SQLSTATE[HY000]: General error: 23 not authorized diff --git a/ext/pdo_sqlite/tests/subclasses/pdosqlite_setauthorizer_trampoline_no_leak.phpt b/ext/pdo_sqlite/tests/subclasses/pdosqlite_setauthorizer_trampoline_no_leak.phpt new file mode 100644 index 0000000000000..84b83877b94a0 --- /dev/null +++ b/ext/pdo_sqlite/tests/subclasses/pdosqlite_setauthorizer_trampoline_no_leak.phpt @@ -0,0 +1,36 @@ +--TEST-- +PdoSqlite::setAuthorizer use F ZPP for trampoline callback and does not leak +--EXTENSIONS-- +pdo_sqlite +--FILE-- +newInstanceWithoutConstructor(); + +try { + var_dump($obj->setAuthorizer($callback)); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +DONE +--EXPECT-- +Invalid Pdo\Sqlite object: +Error: Pdo\Sqlite object is uninitialized +DONE diff --git a/ext/pgsql/config.m4 b/ext/pgsql/config.m4 index 48fbbae34ace0..1409f879b52cc 100644 --- a/ext/pgsql/config.m4 +++ b/ext/pgsql/config.m4 @@ -31,6 +31,9 @@ if test "$PHP_PGSQL" != "no"; then PHP_CHECK_LIBRARY([pq], [PQclosePrepared], [AC_DEFINE([HAVE_PG_CLOSE_STMT], [1], [PostgreSQL 17 or later])],, [$PGSQL_LIBS]) + PHP_CHECK_LIBRARY([pq], [PQservice], + [AC_DEFINE([HAVE_PG_SERVICE], [1], [PostgreSQL 18 or later])],, + [$PGSQL_LIBS]) old_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $PGSQL_CFLAGS" diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 036fc5c0572a1..b86909d3aa3ee 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -907,6 +907,7 @@ PHP_FUNCTION(pg_close) #define PHP_PG_HOST 6 #define PHP_PG_VERSION 7 #define PHP_PG_JIT 8 +#define PHP_PG_SERVICE 9 /* php_pgsql_get_link_info */ static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) @@ -991,6 +992,12 @@ static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type PQclear(res); return; } +#if defined(HAVE_PG_SERVICE) + case PHP_PG_SERVICE: { + result = PQservice(pgsql); + break; + } +#endif EMPTY_SWITCH_DEFAULT_CASE() } if (result) { @@ -1047,6 +1054,13 @@ PHP_FUNCTION(pg_jit) php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_JIT); } +#if defined(HAVE_PG_SERVICE) +PHP_FUNCTION(pg_service) +{ + php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_SERVICE); +} +#endif + /* Returns the value of a server parameter */ PHP_FUNCTION(pg_parameter_status) { @@ -1670,8 +1684,7 @@ static zend_string *get_field_name(PGconn *pgsql, Oid oid) continue; } - char *end_ptr; - Oid tmp_oid = strtoul(tmp_oid_str, &end_ptr, 10); + Oid tmp_oid = strtoul(tmp_oid_str, NULL, 10); zend_string *name = zend_string_init(tmp_name, strlen(tmp_name), 0); zend_hash_index_update_ptr(&PGG(field_oids), tmp_oid, name); @@ -2173,17 +2186,18 @@ PHP_FUNCTION(pg_fetch_all_columns) RETURN_THROWS(); } - array_init(return_value); - if ((pg_numrows = PQntuples(pgsql_result)) <= 0) { - return; + RETURN_EMPTY_ARRAY(); } + array_init_size(return_value, pg_numrows); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); + for (pg_row = 0; pg_row < pg_numrows; pg_row++) { if (PQgetisnull(pgsql_result, pg_row, (int)colno)) { - add_next_index_null(return_value); + add_index_null(return_value, pg_row); } else { - add_next_index_string(return_value, PQgetvalue(pgsql_result, pg_row, (int)colno)); + add_index_string(return_value, pg_row, PQgetvalue(pgsql_result, pg_row, (int)colno)); } } } @@ -3350,6 +3364,7 @@ PHP_FUNCTION(pg_copy_to) PQclear(pgsql_result); array_init(return_value); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); while (!copydone) { int ret = PQgetCopyData(pgsql, &csv, 0); @@ -3391,11 +3406,12 @@ static zend_result pgsql_copy_from_query(PGconn *pgsql, PGresult *pgsql_result, if (UNEXPECTED(!tmp)) { return FAILURE; } - zend_string *zquery = zend_string_alloc(ZSTR_LEN(tmp) + 1, false); + zend_string *zquery = zend_string_alloc(ZSTR_LEN(tmp) + 2, false); memcpy(ZSTR_VAL(zquery), ZSTR_VAL(tmp), ZSTR_LEN(tmp) + 1); ZSTR_LEN(zquery) = ZSTR_LEN(tmp); - if (ZSTR_LEN(tmp) > 0 && ZSTR_VAL(zquery)[ZSTR_LEN(tmp)] != '\n') { + if (ZSTR_LEN(tmp) > 0 && ZSTR_VAL(zquery)[ZSTR_LEN(tmp) - 1] != '\n') { ZSTR_VAL(zquery)[ZSTR_LEN(tmp)] = '\n'; + ZSTR_VAL(zquery)[ZSTR_LEN(tmp) + 1] = '\0'; ZSTR_LEN(zquery) ++; } if (PQputCopyData(pgsql, ZSTR_VAL(zquery), ZSTR_LEN(zquery)) != 1) { @@ -6244,7 +6260,7 @@ PHP_FUNCTION(pg_put_copy_end) { zval *pgsql_link; pgsql_link_handle *link; - zend_string *error; + zend_string *error = NULL; char *err = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) diff --git a/ext/pgsql/pgsql.stub.php b/ext/pgsql/pgsql.stub.php index 22177fec367b3..04e648eff8d50 100644 --- a/ext/pgsql/pgsql.stub.php +++ b/ext/pgsql/pgsql.stub.php @@ -508,6 +508,9 @@ function pg_version(?PgSql\Connection $connection = null): array {} */ function pg_jit(?PgSql\Connection $connection = null): array {} +#ifdef HAVE_PG_SERVICE + function pg_service(?PgSql\Connection $connection = null): string {} +#endif /** * @param PgSql\Connection|string $connection * @refcount 1 @@ -971,7 +974,7 @@ function pg_socket_poll($socket, int $read, int $write, int $timeout = -1): int function pg_set_chunked_rows_size(PgSql\Connection $connection, int $size): bool {} #endif #ifdef HAVE_PG_CLOSE_STMT - function pg_close_stmt(Pgsql\Connection $connection, string $statement_name): Pgsql\Result|false {} + function pg_close_stmt(Pgsql\Connection $connection, string $statement_name): PgSql\Result|false {} #endif } diff --git a/ext/pgsql/pgsql_arginfo.h b/ext/pgsql/pgsql_arginfo.h index cb79f83971301..cb58645e5e9f5 100644 --- a/ext/pgsql/pgsql_arginfo.h +++ b/ext/pgsql/pgsql_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 13be2a3c9a4ef4a72c0a67019b7400418752b603 */ + * Stub hash: 3cf44ca06d11cad086829d3d04900ade3cacb88b */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pg_connect, 0, 1, PgSql\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, connection_string, IS_STRING, 0) @@ -38,6 +38,12 @@ ZEND_END_ARG_INFO() #define arginfo_pg_jit arginfo_pg_version +#if defined(HAVE_PG_SERVICE) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pg_service, 0, 0, IS_STRING, 0) + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, connection, PgSql\\Connection, 1, "null") +ZEND_END_ARG_INFO() +#endif + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_pg_parameter_status, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) ZEND_ARG_INFO(0, connection) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) @@ -496,7 +502,7 @@ ZEND_END_ARG_INFO() #endif #if defined(HAVE_PG_CLOSE_STMT) -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pg_close_stmt, 0, 2, Pgsql\\Result, MAY_BE_FALSE) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pg_close_stmt, 0, 2, PgSql\\Result, MAY_BE_FALSE) ZEND_ARG_OBJ_INFO(0, connection, Pgsql\\Connection, 0) ZEND_ARG_TYPE_INFO(0, statement_name, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -514,6 +520,9 @@ ZEND_FUNCTION(pg_tty); ZEND_FUNCTION(pg_host); ZEND_FUNCTION(pg_version); ZEND_FUNCTION(pg_jit); +#if defined(HAVE_PG_SERVICE) +ZEND_FUNCTION(pg_service); +#endif ZEND_FUNCTION(pg_parameter_status); ZEND_FUNCTION(pg_ping); ZEND_FUNCTION(pg_query); @@ -623,6 +632,9 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(pg_host, arginfo_pg_host) ZEND_FE(pg_version, arginfo_pg_version) ZEND_FE(pg_jit, arginfo_pg_jit) +#if defined(HAVE_PG_SERVICE) + ZEND_FE(pg_service, arginfo_pg_service) +#endif ZEND_FE(pg_parameter_status, arginfo_pg_parameter_status) ZEND_FE(pg_ping, arginfo_pg_ping) ZEND_FE(pg_query, arginfo_pg_query) diff --git a/ext/pgsql/tests/gh18148.phpt b/ext/pgsql/tests/gh18148.phpt new file mode 100644 index 0000000000000..6cc2a2542086f --- /dev/null +++ b/ext/pgsql/tests/gh18148.phpt @@ -0,0 +1,24 @@ +--TEST-- +Fix GH-18148 pg_copy_from() command position offset when giving explicit \n terminator +--EXTENSIONS-- +pgsql +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(true) diff --git a/ext/pgsql/tests/pg_service.phpt b/ext/pgsql/tests/pg_service.phpt new file mode 100644 index 0000000000000..0ce1be7285ebc --- /dev/null +++ b/ext/pgsql/tests/pg_service.phpt @@ -0,0 +1,19 @@ +--TEST-- +PostgreSQL connection service field support +--EXTENSIONS-- +pgsql +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +string(%d) "%A" diff --git a/ext/posix/posix.c b/ext/posix/posix.c index d465e5230938a..68d47840c5e20 100644 --- a/ext/posix/posix.c +++ b/ext/posix/posix.c @@ -236,10 +236,11 @@ PHP_FUNCTION(posix_getgroups) RETURN_FALSE; } - array_init(return_value); + array_init_size(return_value, result); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for (i=0; igr_name); if (g->gr_passwd) { @@ -1174,7 +1176,8 @@ PHP_FUNCTION(posix_getrlimit) RETURN_FALSE; } - array_init(return_value); + array_init_size(return_value, 2); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); if (rl.rlim_cur == RLIM_INFINITY) { add_next_index_stringl(return_value, UNLIMITED_STRING, sizeof(UNLIMITED_STRING)-1); } else { diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index bc8ffbdd8bd8e..bff617cfb61de 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -306,6 +306,7 @@ static void _const_string(smart_str *str, const char *name, zval *value, const c static void _function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, const char* indent); static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, const char* indent); static void _class_const_string(smart_str *str, const zend_string *name, zend_class_constant *c, const char* indent); +static void _enum_case_string(smart_str *str, const zend_string *name, zend_class_constant *c, const char* indent); static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const char *indent); static void _extension_string(smart_str *str, const zend_module_entry *module, const char *indent); static void _zend_extension_string(smart_str *str, const zend_extension *extension, const char *indent); @@ -330,38 +331,48 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const kind = "Interface"; } else if (ce->ce_flags & ZEND_ACC_TRAIT) { kind = "Trait"; + } else if (ce->ce_flags & ZEND_ACC_ENUM) { + kind = "Enum"; } smart_str_append_printf(str, "%s%s [ ", indent, kind); } - smart_str_append_printf(str, (ce->type == ZEND_USER_CLASS) ? "type == ZEND_USER_CLASS) ? "type == ZEND_INTERNAL_CLASS && ce->info.internal.module) { smart_str_append_printf(str, ":%s", ce->info.internal.module->name); } - smart_str_append_printf(str, "> "); + smart_str_appends(str, "> "); if (ce->get_iterator != NULL) { - smart_str_append_printf(str, " "); + smart_str_appends(str, " "); } if (ce->ce_flags & ZEND_ACC_INTERFACE) { - smart_str_append_printf(str, "interface "); + smart_str_appends(str, "interface "); } else if (ce->ce_flags & ZEND_ACC_TRAIT) { - smart_str_append_printf(str, "trait "); + smart_str_appends(str, "trait "); + } else if (ce->ce_flags & ZEND_ACC_ENUM) { + smart_str_appends(str, "enum "); } else { if (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { - smart_str_append_printf(str, "abstract "); + smart_str_appends(str, "abstract "); } if (ce->ce_flags & ZEND_ACC_FINAL) { - smart_str_append_printf(str, "final "); + smart_str_appends(str, "final "); } if (ce->ce_flags & ZEND_ACC_READONLY_CLASS) { - smart_str_append_printf(str, "readonly "); + smart_str_appends(str, "readonly "); } - smart_str_append_printf(str, "class "); + smart_str_appends(str, "class "); } - smart_str_append_printf(str, "%s", ZSTR_VAL(ce->name)); + smart_str_append(str, ce->name); if (ce->parent) { smart_str_append_printf(str, " extends %s", ZSTR_VAL(ce->parent->name)); } + // Show backing type of enums + if ((ce->ce_flags & ZEND_ACC_ENUM) && (ce->enum_backing_type != IS_UNDEF)) { + smart_str_appends(str, + ce->enum_backing_type == IS_STRING ? ": string" : ": int" + ); + } if (ce->num_interfaces) { uint32_t i; @@ -375,7 +386,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const smart_str_append_printf(str, ", %s", ZSTR_VAL(ce->interfaces[i]->name)); } } - smart_str_append_printf(str, " ] {\n"); + smart_str_appends(str, " ] {\n"); /* The information where a class is declared is only available for user classes */ if (ce->type == ZEND_USER_CLASS) { @@ -384,23 +395,49 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const } /* Constants */ - smart_str_append_printf(str, "\n"); - count = zend_hash_num_elements(&ce->constants_table); - smart_str_append_printf(str, "%s - Constants [%d] {\n", indent, count); - if (count > 0) { + uint32_t total_count = zend_hash_num_elements(&ce->constants_table); + uint32_t constant_count = 0; + uint32_t enum_case_count = 0; + smart_str constant_str = {0}; + smart_str enum_case_str = {0}; + /* So that we don't need to loop through all of the constants multiple + * times (count the constants vs. enum cases, print the constants, print + * the enum cases) use some temporary helper smart strings. */ + if (total_count > 0) { zend_string *key; zend_class_constant *c; ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), key, c) { - _class_const_string(str, key, c, ZSTR_VAL(sub_indent)); + if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE) { + _enum_case_string(&enum_case_str, key, c, ZSTR_VAL(sub_indent)); + enum_case_count++; + } else { + _class_const_string(&constant_str, key, c, ZSTR_VAL(sub_indent)); + constant_count++; + } if (UNEXPECTED(EG(exception))) { zend_string_release(sub_indent); + smart_str_free(&enum_case_str); + smart_str_free(&constant_str); return; } } ZEND_HASH_FOREACH_END(); } + // Enum cases go first, but the heading is only shown if there are any + if (enum_case_count) { + smart_str_appendc(str, '\n'); + smart_str_append_printf(str, "%s - Enum cases [%d] {\n", indent, enum_case_count); + smart_str_append_smart_str(str, &enum_case_str); + smart_str_append_printf(str, "%s }\n", indent); + } + smart_str_appendc(str, '\n'); + smart_str_append_printf(str, "%s - Constants [%d] {\n", indent, constant_count); + smart_str_append_smart_str(str, &constant_str); smart_str_append_printf(str, "%s }\n", indent); + smart_str_free(&enum_case_str); + smart_str_free(&constant_str); + /* Static properties */ /* counting static properties */ count = zend_hash_num_elements(&ce->properties_info); @@ -453,12 +490,12 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const if ((mptr->common.fn_flags & ZEND_ACC_STATIC) && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce)) { - smart_str_append_printf(str, "\n"); + smart_str_appendc(str, '\n'); _function_string(str, mptr, ce, ZSTR_VAL(sub_indent)); } } ZEND_HASH_FOREACH_END(); } else { - smart_str_append_printf(str, "\n"); + smart_str_appendc(str, '\n'); } smart_str_append_printf(str, "%s }\n", indent); @@ -529,7 +566,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const smart_str_append_printf(str, "\n%s - Methods [%d] {", indent, count); smart_str_append_smart_str(str, &method_str); if (!count) { - smart_str_append_printf(str, "\n"); + smart_str_appendc(str, '\n'); } smart_str_free(&method_str); } else { @@ -553,7 +590,7 @@ static void _const_string(smart_str *str, const char *name, zval *value, const c if (flags & (CONST_PERSISTENT|CONST_NO_FILE_CACHE|CONST_DEPRECATED)) { bool first = true; - smart_str_appends(str, "<"); + smart_str_appendc(str, '<'); #define DUMP_CONST_FLAG(flag, output) \ do { \ @@ -626,6 +663,32 @@ static void _class_const_string(smart_str *str, const zend_string *name, zend_cl } /* }}} */ +static void _enum_case_string(smart_str *str, const zend_string *name, zend_class_constant *c, const char *indent) +{ + if (Z_TYPE(c->value) == IS_CONSTANT_AST && zend_update_class_constant(c, name, c->ce) == FAILURE) { + return; + } + + if (c->doc_comment) { + smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(c->doc_comment)); + } + smart_str_append_printf(str, "%sCase %s", indent, ZSTR_VAL(name)); + if (c->ce->enum_backing_type == IS_UNDEF) { + // No value + smart_str_appendc(str, '\n'); + } else { + /* Has a value, which is the enum instance, get the value from that. + * We know it must be either a string or integer so no need + * for the IS_ARRAY or IS_OBJECT handling that _class_const_string() + * requires. */ + zval *enum_val = zend_enum_fetch_case_value(Z_OBJ(c->value)); + zend_string *tmp_value_str; + zend_string *value_str = zval_get_tmp_string(enum_val, &tmp_value_str); + smart_str_append_printf(str, " = %s\n", ZSTR_VAL(value_str)); + zend_tmp_string_release(tmp_value_str); + } +} + static zend_op *get_recv_op(const zend_op_array *op_array, uint32_t offset) { zend_op *op = op_array->opcodes; @@ -691,7 +754,7 @@ static int format_default_value(smart_str *str, zval *value) { ZEND_ASSERT(!(class->ce_flags & ZEND_ACC_ENUM)); smart_str_appends(str, "object("); smart_str_append(str, class->name); - smart_str_appends(str, ")"); + smart_str_appendc(str, ')'); } else { ZEND_ASSERT(Z_TYPE_P(value) == IS_CONSTANT_AST); zend_string *ast_str = zend_ast_export("", Z_ASTVAL_P(value), ""); @@ -711,9 +774,9 @@ static void _parameter_string(smart_str *str, zend_function *fptr, struct _zend_ { smart_str_append_printf(str, "Parameter #%d [ ", offset); if (!required) { - smart_str_append_printf(str, " "); + smart_str_appends(str, " "); } else { - smart_str_append_printf(str, " "); + smart_str_appends(str, " "); } if (ZEND_TYPE_IS_SET(arg_info->type)) { zend_string *type_str = zend_type_to_string(arg_info->type); @@ -799,7 +862,7 @@ static void _function_closure_string(smart_str *str, const zend_function *fptr, return; } - smart_str_append_printf(str, "\n"); + smart_str_appendc(str, '\n'); smart_str_append_printf(str, "%s- Bound Variables [%u] {\n", indent, count); i = 0; ZEND_HASH_MAP_FOREACH_STR_KEY(static_variables, key) { @@ -827,8 +890,8 @@ static void _function_string(smart_str *str, zend_function *fptr, zend_class_ent } smart_str_appendl(str, indent, strlen(indent)); - smart_str_append_printf(str, fptr->common.fn_flags & ZEND_ACC_CLOSURE ? "Closure [ " : (fptr->common.scope ? "Method [ " : "Function [ ")); - smart_str_append_printf(str, (fptr->type == ZEND_USER_FUNCTION) ? "common.fn_flags & ZEND_ACC_CLOSURE ? "Closure [ " : (fptr->common.scope ? "Method [ " : "Function [ ")); + smart_str_appends(str, (fptr->type == ZEND_USER_FUNCTION) ? "common.fn_flags & ZEND_ACC_DEPRECATED) { smart_str_appends(str, ", deprecated"); } @@ -1039,7 +1102,7 @@ static void _extension_class_string(zend_class_entry *ce, zend_string *key, smar if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) { /* dump class if it is not an alias */ if (zend_string_equals_ci(ce->name, key)) { - smart_str_append_printf(str, "\n"); + smart_str_appendc(str, '\n'); _class_string(str, ce, NULL, indent); (*num_classes)++; } @@ -1102,7 +1165,7 @@ static void _extension_string(smart_str *str, const zend_module_entry *module, c _extension_ini_string(ini_entry, &str_ini, indent, module->module_number); } ZEND_HASH_FOREACH_END(); if (smart_str_get_len(&str_ini) > 0) { - smart_str_append_printf(str, "\n - INI {\n"); + smart_str_appends(str, "\n - INI {\n"); smart_str_append_smart_str(str, &str_ini); smart_str_append_printf(str, "%s }\n", indent); } @@ -1137,7 +1200,7 @@ static void _extension_string(smart_str *str, const zend_module_entry *module, c if (fptr->common.type==ZEND_INTERNAL_FUNCTION && fptr->internal_function.module == module) { if (first) { - smart_str_append_printf(str, "\n - Functions {\n"); + smart_str_appends(str, "\n - Functions {\n"); first = 0; } _function_string(str, fptr, NULL, " "); @@ -2608,7 +2671,7 @@ ZEND_METHOD(ReflectionParameter, __toString) /* }}} */ -/* {{{ Returns this parameters's name */ +/* {{{ Returns this parameter's name */ ZEND_METHOD(ReflectionParameter, getName) { reflection_object *intern; @@ -3107,7 +3170,7 @@ ZEND_METHOD(ReflectionUnionType, getTypes) array_init(return_value); if (ZEND_TYPE_HAS_LIST(param->type)) { - zend_type *list_type; + const zend_type *list_type; ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(param->type), list_type) { append_type(return_value, *list_type); } ZEND_TYPE_LIST_FOREACH_END(); @@ -3158,7 +3221,7 @@ ZEND_METHOD(ReflectionIntersectionType, getTypes) { reflection_object *intern; type_reference *param; - zend_type *list_type; + const zend_type *list_type; ZEND_PARSE_PARAMETERS_NONE(); GET_REFLECTION_OBJECT_PTR(param); diff --git a/ext/reflection/tests/ReflectionEnumUnitCase_getEnum.phpt b/ext/reflection/tests/ReflectionEnumUnitCase_getEnum.phpt index f9c05d2f6e596..c3d925913a481 100644 --- a/ext/reflection/tests/ReflectionEnumUnitCase_getEnum.phpt +++ b/ext/reflection/tests/ReflectionEnumUnitCase_getEnum.phpt @@ -11,11 +11,14 @@ echo (new ReflectionEnumUnitCase(Foo::class, 'Bar'))->getEnum(); ?> --EXPECTF-- -Class [ final class Foo implements UnitEnum ] { +Enum [ enum Foo implements UnitEnum ] { @@ %sReflectionEnumUnitCase_getEnum.php 3-5 - - Constants [1] { - Constant [ public Foo Bar ] { Object } + - Enum cases [1] { + Case Bar + } + + - Constants [0] { } - Static properties [0] { diff --git a/ext/reflection/tests/ReflectionEnum_toString.phpt b/ext/reflection/tests/ReflectionEnum_toString.phpt index 91ef587a9a3a4..5407afba682ae 100644 --- a/ext/reflection/tests/ReflectionEnum_toString.phpt +++ b/ext/reflection/tests/ReflectionEnum_toString.phpt @@ -11,11 +11,14 @@ echo new ReflectionEnum(Foo::class); ?> --EXPECTF-- -Class [ final class Foo implements UnitEnum ] { +Enum [ enum Foo implements UnitEnum ] { @@ %sReflectionEnum_toString.php 3-5 - - Constants [1] { - Constant [ public Foo Bar ] { Object } + - Enum cases [1] { + Case Bar + } + + - Constants [0] { } - Static properties [0] { diff --git a/ext/reflection/tests/ReflectionEnum_toString_backed_int.phpt b/ext/reflection/tests/ReflectionEnum_toString_backed_int.phpt new file mode 100644 index 0000000000000..24ffbf918eaaa --- /dev/null +++ b/ext/reflection/tests/ReflectionEnum_toString_backed_int.phpt @@ -0,0 +1,147 @@ +--TEST-- +ReflectionEnum::__toString() (larger case, int-backed) +--FILE-- +name . " = " . $this->value; + } +} + +$r = new ReflectionClass( MyBool::class ); +echo $r; +echo "\n"; +$r = new ReflectionEnum( MyBool::class ); +echo $r; + +var_export( MyBool::cases() ); + +?> +--EXPECTF-- +Enum [ enum MyBool: int implements MyStringable, UnitEnum, BackedEnum ] { + @@ %sReflectionEnum_toString_backed_int.php 7-16 + + - Enum cases [2] { + Case MyFalse = 0 + Case MyTrue = 1 + } + + - Constants [1] { + Constant [ public MyBool OtherTrue ] { Object } + } + + - Static properties [0] { + } + + - Static methods [3] { + Method [ static public method cases ] { + + - Parameters [0] { + } + - Return [ array ] + } + + Method [ static public method from ] { + + - Parameters [1] { + Parameter #0 [ string|int $value ] + } + - Return [ static ] + } + + Method [ static public method tryFrom ] { + + - Parameters [1] { + Parameter #0 [ string|int $value ] + } + - Return [ ?static ] + } + } + + - Properties [2] { + Property [ public protected(set) readonly string $name ] + Property [ public protected(set) readonly int $value ] + } + + - Methods [1] { + Method [ public method toString ] { + @@ %sReflectionEnum_toString_backed_int.php 13 - 15 + + - Parameters [0] { + } + - Return [ string ] + } + } +} + +Enum [ enum MyBool: int implements MyStringable, UnitEnum, BackedEnum ] { + @@ %sReflectionEnum_toString_backed_int.php 7-16 + + - Enum cases [2] { + Case MyFalse = 0 + Case MyTrue = 1 + } + + - Constants [1] { + Constant [ public MyBool OtherTrue ] { Object } + } + + - Static properties [0] { + } + + - Static methods [3] { + Method [ static public method cases ] { + + - Parameters [0] { + } + - Return [ array ] + } + + Method [ static public method from ] { + + - Parameters [1] { + Parameter #0 [ string|int $value ] + } + - Return [ static ] + } + + Method [ static public method tryFrom ] { + + - Parameters [1] { + Parameter #0 [ string|int $value ] + } + - Return [ ?static ] + } + } + + - Properties [2] { + Property [ public protected(set) readonly string $name ] + Property [ public protected(set) readonly int $value ] + } + + - Methods [1] { + Method [ public method toString ] { + @@ %sReflectionEnum_toString_backed_int.php 13 - 15 + + - Parameters [0] { + } + - Return [ string ] + } + } +} +array ( + 0 => + \MyBool::MyFalse, + 1 => + \MyBool::MyTrue, +) diff --git a/ext/reflection/tests/ReflectionEnum_toString_backed_string.phpt b/ext/reflection/tests/ReflectionEnum_toString_backed_string.phpt new file mode 100644 index 0000000000000..4c38d2b624b39 --- /dev/null +++ b/ext/reflection/tests/ReflectionEnum_toString_backed_string.phpt @@ -0,0 +1,147 @@ +--TEST-- +ReflectionEnum::__toString() (larger case, string-backed) +--FILE-- +name . " = " . $this->value; + } +} + +$r = new ReflectionClass( MyBool::class ); +echo $r; +echo "\n"; +$r = new ReflectionEnum( MyBool::class ); +echo $r; + +var_export( MyBool::cases() ); + +?> +--EXPECTF-- +Enum [ enum MyBool: string implements MyStringable, UnitEnum, BackedEnum ] { + @@ %sReflectionEnum_toString_backed_string.php 7-16 + + - Enum cases [2] { + Case MyFalse = ~FALSE~ + Case MyTrue = ~TRUE~ + } + + - Constants [1] { + Constant [ public MyBool OtherTrue ] { Object } + } + + - Static properties [0] { + } + + - Static methods [3] { + Method [ static public method cases ] { + + - Parameters [0] { + } + - Return [ array ] + } + + Method [ static public method from ] { + + - Parameters [1] { + Parameter #0 [ string|int $value ] + } + - Return [ static ] + } + + Method [ static public method tryFrom ] { + + - Parameters [1] { + Parameter #0 [ string|int $value ] + } + - Return [ ?static ] + } + } + + - Properties [2] { + Property [ public protected(set) readonly string $name ] + Property [ public protected(set) readonly string $value ] + } + + - Methods [1] { + Method [ public method toString ] { + @@ %sReflectionEnum_toString_backed_string.php 13 - 15 + + - Parameters [0] { + } + - Return [ string ] + } + } +} + +Enum [ enum MyBool: string implements MyStringable, UnitEnum, BackedEnum ] { + @@ %sReflectionEnum_toString_backed_string.php 7-16 + + - Enum cases [2] { + Case MyFalse = ~FALSE~ + Case MyTrue = ~TRUE~ + } + + - Constants [1] { + Constant [ public MyBool OtherTrue ] { Object } + } + + - Static properties [0] { + } + + - Static methods [3] { + Method [ static public method cases ] { + + - Parameters [0] { + } + - Return [ array ] + } + + Method [ static public method from ] { + + - Parameters [1] { + Parameter #0 [ string|int $value ] + } + - Return [ static ] + } + + Method [ static public method tryFrom ] { + + - Parameters [1] { + Parameter #0 [ string|int $value ] + } + - Return [ ?static ] + } + } + + - Properties [2] { + Property [ public protected(set) readonly string $name ] + Property [ public protected(set) readonly string $value ] + } + + - Methods [1] { + Method [ public method toString ] { + @@ %sReflectionEnum_toString_backed_string.php 13 - 15 + + - Parameters [0] { + } + - Return [ string ] + } + } +} +array ( + 0 => + \MyBool::MyFalse, + 1 => + \MyBool::MyTrue, +) diff --git a/ext/reflection/tests/ReflectionEnum_toString_unbacked.phpt b/ext/reflection/tests/ReflectionEnum_toString_unbacked.phpt new file mode 100644 index 0000000000000..ec3d73ab70452 --- /dev/null +++ b/ext/reflection/tests/ReflectionEnum_toString_unbacked.phpt @@ -0,0 +1,123 @@ +--TEST-- +ReflectionEnum::__toString() (larger case, unbacked) +--FILE-- +name; + } +} + +$r = new ReflectionClass( Suit::class ); +echo $r; +echo "\n"; +$r = new ReflectionEnum( Suit::class ); +echo $r; + +var_export( Suit::cases() ); + +?> +--EXPECTF-- +Enum [ enum Suit implements MyStringable, UnitEnum ] { + @@ %sReflectionEnum_toString_unbacked.php 7-18 + + - Enum cases [4] { + Case Hearts + Case Diamonds + Case Clubs + Case Spades + } + + - Constants [1] { + Constant [ public Suit OtherHearts ] { Object } + } + + - Static properties [0] { + } + + - Static methods [1] { + Method [ static public method cases ] { + + - Parameters [0] { + } + - Return [ array ] + } + } + + - Properties [1] { + Property [ public protected(set) readonly string $name ] + } + + - Methods [1] { + Method [ public method toString ] { + @@ %sReflectionEnum_toString_unbacked.php 15 - 17 + + - Parameters [0] { + } + - Return [ string ] + } + } +} + +Enum [ enum Suit implements MyStringable, UnitEnum ] { + @@ %sReflectionEnum_toString_unbacked.php 7-18 + + - Enum cases [4] { + Case Hearts + Case Diamonds + Case Clubs + Case Spades + } + + - Constants [1] { + Constant [ public Suit OtherHearts ] { Object } + } + + - Static properties [0] { + } + + - Static methods [1] { + Method [ static public method cases ] { + + - Parameters [0] { + } + - Return [ array ] + } + } + + - Properties [1] { + Property [ public protected(set) readonly string $name ] + } + + - Methods [1] { + Method [ public method toString ] { + @@ %sReflectionEnum_toString_unbacked.php 15 - 17 + + - Parameters [0] { + } + - Return [ string ] + } + } +} +array ( + 0 => + \Suit::Hearts, + 1 => + \Suit::Diamonds, + 2 => + \Suit::Clubs, + 3 => + \Suit::Spades, +) diff --git a/ext/session/mod_user_class.c b/ext/session/mod_user_class.c index 853db659887be..22be2cd151949 100644 --- a/ext/session/mod_user_class.c +++ b/ext/session/mod_user_class.c @@ -34,7 +34,6 @@ RETURN_FALSE; \ } -/* {{{ Wraps the old open handler */ PHP_METHOD(SessionHandler, open) { char *save_path = NULL, *session_name = NULL; @@ -60,9 +59,7 @@ PHP_METHOD(SessionHandler, open) RETURN_BOOL(SUCCESS == ret); } -/* }}} */ -/* {{{ Wraps the old close handler */ PHP_METHOD(SessionHandler, close) { zend_result ret; @@ -84,9 +81,7 @@ PHP_METHOD(SessionHandler, close) RETURN_BOOL(SUCCESS == ret); } -/* }}} */ -/* {{{ Wraps the old read handler */ PHP_METHOD(SessionHandler, read) { zend_string *val; @@ -104,9 +99,7 @@ PHP_METHOD(SessionHandler, read) RETURN_STR(val); } -/* }}} */ -/* {{{ Wraps the old write handler */ PHP_METHOD(SessionHandler, write) { zend_string *key, *val; @@ -119,9 +112,7 @@ PHP_METHOD(SessionHandler, write) RETURN_BOOL(SUCCESS == PS(default_mod)->s_write(&PS(mod_data), key, val, PS(gc_maxlifetime))); } -/* }}} */ -/* {{{ Wraps the old destroy handler */ PHP_METHOD(SessionHandler, destroy) { zend_string *key; @@ -134,9 +125,7 @@ PHP_METHOD(SessionHandler, destroy) RETURN_BOOL(SUCCESS == PS(default_mod)->s_destroy(&PS(mod_data), key)); } -/* }}} */ -/* {{{ Wraps the old gc handler */ PHP_METHOD(SessionHandler, gc) { zend_long maxlifetime; @@ -153,9 +142,7 @@ PHP_METHOD(SessionHandler, gc) } RETURN_LONG(nrdels); } -/* }}} */ -/* {{{ Wraps the old create_sid handler */ PHP_METHOD(SessionHandler, create_sid) { zend_string *id; @@ -170,4 +157,3 @@ PHP_METHOD(SessionHandler, create_sid) RETURN_STR(id); } -/* }}} */ diff --git a/ext/session/session.c b/ext/session/session.c index ae6576856e48e..fd877483c0a6f 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -105,7 +105,7 @@ static zend_result php_session_abort(void); static int my_module_number = 0; /* Dispatched by RINIT and by php_session_destroy */ -static inline void php_rinit_session_globals(void) /* {{{ */ +static inline void php_rinit_session_globals(void) { /* Do NOT init PS(mod_user_names) here! */ /* TODO: These could be moved to MINIT and removed. These should be initialized by php_rshutdown_session_globals() always when execution is finished. */ @@ -120,9 +120,8 @@ static inline void php_rinit_session_globals(void) /* {{{ */ PS(module_number) = my_module_number; ZVAL_UNDEF(&PS(http_session_vars)); } -/* }}} */ -static inline void php_session_headers_already_sent_error(int severity, const char *message) { /* {{{ */ +static inline void php_session_headers_already_sent_error(int severity, const char *message) { const char *output_start_filename = php_output_get_start_filename(); int output_start_lineno = php_output_get_start_lineno(); if (output_start_filename != NULL) { @@ -131,9 +130,8 @@ static inline void php_session_headers_already_sent_error(int severity, const ch php_error_docref(NULL, severity, "%s", message); } } -/* }}} */ -static inline void php_session_session_already_started_error(int severity, const char *message) { /* {{{ */ +static inline void php_session_session_already_started_error(int severity, const char *message) { if (PS(session_started_filename) != NULL) { php_error_docref(NULL, severity, "%s (started from %s on line %"PRIu32")", message, ZSTR_VAL(PS(session_started_filename)), PS(session_started_lineno)); } else if (PS(auto_start)) { @@ -143,9 +141,8 @@ static inline void php_session_session_already_started_error(int severity, const php_error_docref(NULL, severity, "%s", message); } } -/* }}} */ -static inline void php_session_cleanup_filename(void) /* {{{ */ +static inline void php_session_cleanup_filename(void) { if (PS(session_started_filename)) { zend_string_release(PS(session_started_filename)); @@ -153,10 +150,9 @@ static inline void php_session_cleanup_filename(void) /* {{{ */ PS(session_started_lineno) = 0; } } -/* }}} */ /* Dispatched by RSHUTDOWN and by php_session_destroy */ -static void php_rshutdown_session_globals(void) /* {{{ */ +static void php_rshutdown_session_globals(void) { /* Do NOT destroy PS(mod_user_names) here! */ if (!Z_ISUNDEF(PS(http_session_vars))) { @@ -189,9 +185,8 @@ static void php_rshutdown_session_globals(void) /* {{{ */ /* Set session status to prevent error while restoring save handler INI value. */ PS(session_status) = php_session_none; } -/* }}} */ -PHPAPI zend_result php_session_destroy(void) /* {{{ */ +PHPAPI zend_result php_session_destroy(void) { zend_result retval = SUCCESS; @@ -212,9 +207,8 @@ PHPAPI zend_result php_session_destroy(void) /* {{{ */ return retval; } -/* }}} */ -PHPAPI void php_add_session_var(zend_string *name) /* {{{ */ +PHPAPI void php_add_session_var(zend_string *name) { IF_SESSION_VARS() { zval *sess_var = Z_REFVAL(PS(http_session_vars)); @@ -226,9 +220,8 @@ PHPAPI void php_add_session_var(zend_string *name) /* {{{ */ } } } -/* }}} */ -PHPAPI zval* php_set_session_var(zend_string *name, zval *state_val, php_unserialize_data_t *var_hash) /* {{{ */ +PHPAPI zval* php_set_session_var(zend_string *name, zval *state_val, php_unserialize_data_t *var_hash) { IF_SESSION_VARS() { zval *sess_var = Z_REFVAL(PS(http_session_vars)); @@ -237,16 +230,14 @@ PHPAPI zval* php_set_session_var(zend_string *name, zval *state_val, php_unseria } return NULL; } -/* }}} */ -PHPAPI zval* php_get_session_var(zend_string *name) /* {{{ */ +PHPAPI zval* php_get_session_var(zend_string *name) { IF_SESSION_VARS() { return zend_hash_find(Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars))), name); } return NULL; } -/* }}} */ PHPAPI zval* php_get_session_var_str(const char *name, size_t name_len) { @@ -256,7 +247,7 @@ PHPAPI zval* php_get_session_var_str(const char *name, size_t name_len) return NULL; } -static void php_session_track_init(void) /* {{{ */ +static void php_session_track_init(void) { zval session_vars; zend_string *var_name = ZSTR_INIT_LITERAL("_SESSION", 0); @@ -273,9 +264,8 @@ static void php_session_track_init(void) /* {{{ */ zend_hash_update_ind(&EG(symbol_table), var_name, &PS(http_session_vars)); zend_string_release_ex(var_name, 0); } -/* }}} */ -static zend_string *php_session_encode(void) /* {{{ */ +static zend_string *php_session_encode(void) { IF_SESSION_VARS() { ZEND_ASSERT(PS(serializer)); @@ -285,7 +275,6 @@ static zend_string *php_session_encode(void) /* {{{ */ } return NULL; } -/* }}} */ static ZEND_COLD void php_session_cancel_decode(void) { @@ -294,7 +283,7 @@ static ZEND_COLD void php_session_cancel_decode(void) php_error_docref(NULL, E_WARNING, "Failed to decode session object. Session has been destroyed"); } -static zend_result php_session_decode(zend_string *data) /* {{{ */ +static zend_result php_session_decode(zend_string *data) { ZEND_ASSERT(PS(serializer)); zend_result result = SUCCESS; @@ -309,7 +298,6 @@ static zend_result php_session_decode(zend_string *data) /* {{{ */ } zend_end_try(); return result; } -/* }}} */ /* * Note that we cannot use the BASE64 alphabet here, because @@ -319,7 +307,7 @@ static zend_result php_session_decode(zend_string *data) /* {{{ */ static const char hexconvtab[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,-"; -static void bin_to_readable(unsigned char *in, size_t inlen, char *out, size_t outlen, char nbits) /* {{{ */ +static void bin_to_readable(unsigned char *in, size_t inlen, char *out, size_t outlen, char nbits) { unsigned char *p, *q; unsigned short w; @@ -353,9 +341,8 @@ static void bin_to_readable(unsigned char *in, size_t inlen, char *out, size_t o *out = '\0'; } -/* }}} */ -PHPAPI zend_string *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */ +PHPAPI zend_string *php_session_create_id(PS_CREATE_SID_ARGS) { unsigned char rbuf[PS_MAX_SID_LENGTH]; zend_string *outid; @@ -374,12 +361,11 @@ PHPAPI zend_string *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */ return outid; } -/* }}} */ /* Default session id char validation function allowed by ps_modules. * If you change the logic here, please also update the error message in * ps_modules appropriately */ -PHPAPI zend_result php_session_valid_key(const char *key) /* {{{ */ +PHPAPI zend_result php_session_valid_key(const char *key) { size_t len; const char *p; @@ -406,10 +392,9 @@ PHPAPI zend_result php_session_valid_key(const char *key) /* {{{ */ return SUCCESS; } -/* }}} */ -static zend_long php_session_gc(bool immediate) /* {{{ */ +static zend_long php_session_gc(bool immediate) { zend_long num = -1; bool collect = immediate; @@ -425,9 +410,9 @@ static zend_long php_session_gc(bool immediate) /* {{{ */ } } return num; -} /* }}} */ +} -static zend_result php_session_initialize(void) /* {{{ */ +static zend_result php_session_initialize(void) { zend_string *val = NULL; @@ -520,9 +505,8 @@ static zend_result php_session_initialize(void) /* {{{ */ } return SUCCESS; } -/* }}} */ -static void php_session_save_current_state(int write) /* {{{ */ +static void php_session_save_current_state(int write) { zend_result ret = FAILURE; @@ -578,9 +562,8 @@ static void php_session_save_current_state(int write) /* {{{ */ PS(mod)->s_close(&PS(mod_data)); } } -/* }}} */ -static void php_session_normalize_vars(void) /* {{{ */ +static void php_session_normalize_vars(void) { PS_ENCODE_VARS; @@ -594,13 +577,12 @@ static void php_session_normalize_vars(void) /* {{{ */ ); } } -/* }}} */ /* ************************* * INI Settings/Handlers * ************************* */ -static PHP_INI_MH(OnUpdateSaveHandler) /* {{{ */ +static PHP_INI_MH(OnUpdateSaveHandler) { const ps_module *tmp; int err_type = E_ERROR; @@ -634,9 +616,8 @@ static PHP_INI_MH(OnUpdateSaveHandler) /* {{{ */ return SUCCESS; } -/* }}} */ -static PHP_INI_MH(OnUpdateSerializer) /* {{{ */ +static PHP_INI_MH(OnUpdateSerializer) { const ps_serializer *tmp; @@ -664,9 +645,8 @@ static PHP_INI_MH(OnUpdateSerializer) /* {{{ */ return SUCCESS; } -/* }}} */ -static PHP_INI_MH(OnUpdateSaveDir) /* {{{ */ +static PHP_INI_MH(OnUpdateSaveDir) { SESSION_CHECK_ACTIVE_STATE; SESSION_CHECK_OUTPUT_STATE; @@ -697,10 +677,9 @@ static PHP_INI_MH(OnUpdateSaveDir) /* {{{ */ return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } -/* }}} */ -static PHP_INI_MH(OnUpdateName) /* {{{ */ +static PHP_INI_MH(OnUpdateName) { SESSION_CHECK_ACTIVE_STATE; SESSION_CHECK_OUTPUT_STATE; @@ -729,10 +708,9 @@ static PHP_INI_MH(OnUpdateName) /* {{{ */ return OnUpdateStringUnempty(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } -/* }}} */ -static PHP_INI_MH(OnUpdateCookieLifetime) /* {{{ */ +static PHP_INI_MH(OnUpdateCookieLifetime) { SESSION_CHECK_ACTIVE_STATE; SESSION_CHECK_OUTPUT_STATE; @@ -751,37 +729,32 @@ static PHP_INI_MH(OnUpdateCookieLifetime) /* {{{ */ } return OnUpdateLongGEZero(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } -/* }}} */ -static PHP_INI_MH(OnUpdateSessionLong) /* {{{ */ +static PHP_INI_MH(OnUpdateSessionLong) { SESSION_CHECK_ACTIVE_STATE; SESSION_CHECK_OUTPUT_STATE; return OnUpdateLong(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } -/* }}} */ - -static PHP_INI_MH(OnUpdateSessionString) /* {{{ */ +static PHP_INI_MH(OnUpdateSessionString) { SESSION_CHECK_ACTIVE_STATE; SESSION_CHECK_OUTPUT_STATE; return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } -/* }}} */ -static PHP_INI_MH(OnUpdateSessionBool) /* {{{ */ +static PHP_INI_MH(OnUpdateSessionBool) { SESSION_CHECK_ACTIVE_STATE; SESSION_CHECK_OUTPUT_STATE; return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } -/* }}} */ -static PHP_INI_MH(OnUpdateSidLength) /* {{{ */ +static PHP_INI_MH(OnUpdateSidLength) { zend_long val; char *endptr = NULL; @@ -802,9 +775,8 @@ static PHP_INI_MH(OnUpdateSidLength) /* {{{ */ php_error_docref(NULL, E_WARNING, "session.configuration \"session.sid_length\" must be between 22 and 256"); return FAILURE; } -/* }}} */ -static PHP_INI_MH(OnUpdateSidBits) /* {{{ */ +static PHP_INI_MH(OnUpdateSidBits) { zend_long val; char *endptr = NULL; @@ -825,9 +797,8 @@ static PHP_INI_MH(OnUpdateSidBits) /* {{{ */ php_error_docref(NULL, E_WARNING, "session.configuration \"session.sid_bits_per_character\" must be between 4 and 6"); return FAILURE; } -/* }}} */ -static PHP_INI_MH(OnUpdateSessionGcProbability) /* {{{ */ +static PHP_INI_MH(OnUpdateSessionGcProbability) { SESSION_CHECK_ACTIVE_STATE; SESSION_CHECK_OUTPUT_STATE; @@ -844,9 +815,8 @@ static PHP_INI_MH(OnUpdateSessionGcProbability) /* {{{ */ return SUCCESS; } -/* }}} */ -static PHP_INI_MH(OnUpdateSessionDivisor) /* {{{ */ +static PHP_INI_MH(OnUpdateSessionDivisor) { SESSION_CHECK_ACTIVE_STATE; SESSION_CHECK_OUTPUT_STATE; @@ -863,9 +833,8 @@ static PHP_INI_MH(OnUpdateSessionDivisor) /* {{{ */ return SUCCESS; } -/* }}} */ -static PHP_INI_MH(OnUpdateRfc1867Freq) /* {{{ */ +static PHP_INI_MH(OnUpdateRfc1867Freq) { int tmp = ZEND_ATOL(ZSTR_VAL(new_value)); if(tmp < 0) { @@ -882,7 +851,7 @@ static PHP_INI_MH(OnUpdateRfc1867Freq) /* {{{ */ PS(rfc1867_freq) = tmp; } return SUCCESS; -} /* }}} */ +} static PHP_INI_MH(OnUpdateUseOnlyCookies) { @@ -918,7 +887,6 @@ static PHP_INI_MH(OnUpdateRefererCheck) return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } -/* {{{ PHP_INI */ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("session.save_path", "", PHP_INI_ALL, OnUpdateSaveDir, save_path, php_ps_globals, ps_globals) STD_PHP_INI_ENTRY("session.name", "PHPSESSID", PHP_INI_ALL, OnUpdateName, session_name, php_ps_globals, ps_globals) @@ -961,12 +929,11 @@ PHP_INI_BEGIN() /* Commented out until future discussion */ /* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */ PHP_INI_END() -/* }}} */ /* *************** * Serializers * *************** */ -PS_SERIALIZER_ENCODE_FUNC(php_serialize) /* {{{ */ +PS_SERIALIZER_ENCODE_FUNC(php_serialize) { smart_str buf = {0}; php_serialize_data_t var_hash; @@ -978,9 +945,8 @@ PS_SERIALIZER_ENCODE_FUNC(php_serialize) /* {{{ */ } return buf.s; } -/* }}} */ -PS_SERIALIZER_DECODE_FUNC(php_serialize) /* {{{ */ +PS_SERIALIZER_DECODE_FUNC(php_serialize) { const char *endptr = val + vallen; zval session_vars; @@ -1010,13 +976,12 @@ PS_SERIALIZER_DECODE_FUNC(php_serialize) /* {{{ */ zend_string_release_ex(var_name, 0); return result || !vallen ? SUCCESS : FAILURE; } -/* }}} */ #define PS_BIN_NR_OF_BITS 8 #define PS_BIN_UNDEF (1<<(PS_BIN_NR_OF_BITS-1)) #define PS_BIN_MAX (PS_BIN_UNDEF-1) -PS_SERIALIZER_ENCODE_FUNC(php_binary) /* {{{ */ +PS_SERIALIZER_ENCODE_FUNC(php_binary) { smart_str buf = {0}; php_serialize_data_t var_hash; @@ -1036,9 +1001,8 @@ PS_SERIALIZER_ENCODE_FUNC(php_binary) /* {{{ */ return buf.s; } -/* }}} */ -PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */ +PS_SERIALIZER_DECODE_FUNC(php_binary) { const char *p; const char *endptr = val + vallen; @@ -1077,11 +1041,10 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */ return SUCCESS; } -/* }}} */ #define PS_DELIMITER '|' -PS_SERIALIZER_ENCODE_FUNC(php) /* {{{ */ +PS_SERIALIZER_ENCODE_FUNC(php) { smart_str buf = {0}; php_serialize_data_t var_hash; @@ -1111,9 +1074,8 @@ PS_SERIALIZER_ENCODE_FUNC(php) /* {{{ */ PHP_VAR_SERIALIZE_DESTROY(var_hash); return buf.s; } -/* }}} */ -PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */ +PS_SERIALIZER_DECODE_FUNC(php) { const char *p, *q; const char *endptr = val + vallen; @@ -1160,7 +1122,6 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */ return retval; } -/* }}} */ #define MAX_SERIALIZERS 32 #define PREDEFINED_SERIALIZERS 3 @@ -1171,7 +1132,7 @@ static ps_serializer ps_serializers[MAX_SERIALIZERS + 1] = { PS_SERIALIZER_ENTRY(php_binary) }; -PHPAPI zend_result php_session_register_serializer(const char *name, zend_string *(*encode)(PS_SERIALIZER_ENCODE_ARGS), zend_result (*decode)(PS_SERIALIZER_DECODE_ARGS)) /* {{{ */ +PHPAPI zend_result php_session_register_serializer(const char *name, zend_string *(*encode)(PS_SERIALIZER_ENCODE_ARGS), zend_result (*decode)(PS_SERIALIZER_DECODE_ARGS)) { zend_result ret = FAILURE; @@ -1187,7 +1148,6 @@ PHPAPI zend_result php_session_register_serializer(const char *name, zend_string } return ret; } -/* }}} */ /* ******************* * Storage Modules * @@ -1201,7 +1161,7 @@ static const ps_module *ps_modules[MAX_MODULES + 1] = { ps_user_ptr }; -PHPAPI zend_result php_session_register_module(const ps_module *ptr) /* {{{ */ +PHPAPI zend_result php_session_register_module(const ps_module *ptr) { int ret = FAILURE; @@ -1214,7 +1174,6 @@ PHPAPI zend_result php_session_register_module(const ps_module *ptr) /* {{{ */ } return ret; } -/* }}} */ /* Dummy PS module function */ /* We consider any ID valid (thus also implying that a session with such an ID exists), @@ -1253,7 +1212,7 @@ static const char *week_days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; -static inline void strcpy_gmt(char *ubuf, time_t *when) /* {{{ */ +static inline void strcpy_gmt(char *ubuf, time_t *when) { char buf[MAX_STR]; struct tm tm, *res; @@ -1274,9 +1233,8 @@ static inline void strcpy_gmt(char *ubuf, time_t *when) /* {{{ */ memcpy(ubuf, buf, n); ubuf[n] = '\0'; } -/* }}} */ -static inline void last_modified(void) /* {{{ */ +static inline void last_modified(void) { const char *path; zend_stat_t sb = {0}; @@ -1294,10 +1252,9 @@ static inline void last_modified(void) /* {{{ */ ADD_HEADER(buf); } } -/* }}} */ #define EXPIRES "Expires: " -CACHE_LIMITER_FUNC(public) /* {{{ */ +CACHE_LIMITER_FUNC(public) { char buf[MAX_STR + 1]; struct timeval tv; @@ -1314,9 +1271,8 @@ CACHE_LIMITER_FUNC(public) /* {{{ */ last_modified(); } -/* }}} */ -CACHE_LIMITER_FUNC(private_no_expire) /* {{{ */ +CACHE_LIMITER_FUNC(private_no_expire) { char buf[MAX_STR + 1]; @@ -1325,16 +1281,14 @@ CACHE_LIMITER_FUNC(private_no_expire) /* {{{ */ last_modified(); } -/* }}} */ -CACHE_LIMITER_FUNC(private) /* {{{ */ +CACHE_LIMITER_FUNC(private) { ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT"); CACHE_LIMITER(private_no_expire)(); } -/* }}} */ -CACHE_LIMITER_FUNC(nocache) /* {{{ */ +CACHE_LIMITER_FUNC(nocache) { ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT"); @@ -1344,7 +1298,6 @@ CACHE_LIMITER_FUNC(nocache) /* {{{ */ /* For HTTP/1.0 conforming clients */ ADD_HEADER("Pragma: no-cache"); } -/* }}} */ static const php_session_cache_limiter_t php_session_cache_limiters[] = { CACHE_LIMITER_ENTRY(public) @@ -1354,7 +1307,7 @@ static const php_session_cache_limiter_t php_session_cache_limiters[] = { {0} }; -static int php_session_cache_limiter(void) /* {{{ */ +static int php_session_cache_limiter(void) { const php_session_cache_limiter_t *lim; @@ -1376,7 +1329,6 @@ static int php_session_cache_limiter(void) /* {{{ */ return -1; } -/* }}} */ /* ********************* * Cookie Management * @@ -1425,7 +1377,7 @@ static void php_session_remove_cookie(void) { efree(session_cookie); } -static zend_result php_session_send_cookie(void) /* {{{ */ +static zend_result php_session_send_cookie(void) { smart_str ncookie = {0}; zend_string *date_fmt = NULL; @@ -1499,9 +1451,8 @@ static zend_result php_session_send_cookie(void) /* {{{ */ return SUCCESS; } -/* }}} */ -PHPAPI const ps_module *_php_find_ps_module(const char *name) /* {{{ */ +PHPAPI const ps_module *_php_find_ps_module(const char *name) { const ps_module *ret = NULL; const ps_module **mod; @@ -1515,9 +1466,8 @@ PHPAPI const ps_module *_php_find_ps_module(const char *name) /* {{{ */ } return ret; } -/* }}} */ -PHPAPI const ps_serializer *_php_find_ps_serializer(const char *name) /* {{{ */ +PHPAPI const ps_serializer *_php_find_ps_serializer(const char *name) { const ps_serializer *ret = NULL; const ps_serializer *mod; @@ -1530,7 +1480,6 @@ PHPAPI const ps_serializer *_php_find_ps_serializer(const char *name) /* {{{ */ } return ret; } -/* }}} */ static void ppid2sid(zval *ppid) { ZVAL_DEREF(ppid); @@ -1544,7 +1493,7 @@ static void ppid2sid(zval *ppid) { } -PHPAPI zend_result php_session_reset_id(void) /* {{{ */ +PHPAPI zend_result php_session_reset_id(void) { int module_number = PS(module_number); zval *sid, *data, *ppid; @@ -1614,10 +1563,9 @@ PHPAPI zend_result php_session_reset_id(void) /* {{{ */ } return SUCCESS; } -/* }}} */ -PHPAPI zend_result php_session_start(void) /* {{{ */ +PHPAPI zend_result php_session_start(void) { zval *ppid; zval *data; @@ -1724,9 +1672,8 @@ PHPAPI zend_result php_session_start(void) /* {{{ */ return SUCCESS; } -/* }}} */ -PHPAPI zend_result php_session_flush(int write) /* {{{ */ +PHPAPI zend_result php_session_flush(int write) { if (PS(session_status) == php_session_active) { php_session_save_current_state(write); @@ -1735,14 +1682,13 @@ PHPAPI zend_result php_session_flush(int write) /* {{{ */ } return FAILURE; } -/* }}} */ PHPAPI php_session_status php_get_session_status(void) { return PS(session_status); } -static zend_result php_session_abort(void) /* {{{ */ +static zend_result php_session_abort(void) { if (PS(session_status) == php_session_active) { if (PS(mod_data) || PS(mod_user_implemented)) { @@ -1753,9 +1699,8 @@ static zend_result php_session_abort(void) /* {{{ */ } return FAILURE; } -/* }}} */ -static zend_result php_session_reset(void) /* {{{ */ +static zend_result php_session_reset(void) { if (PS(session_status) == php_session_active && php_session_initialize() == SUCCESS) { @@ -1763,26 +1708,22 @@ static zend_result php_session_reset(void) /* {{{ */ } return FAILURE; } -/* }}} */ /* This API is not used by any PHP modules including session currently. session_adapt_url() may be used to set Session ID to target url without starting "URL-Rewriter" output handler. */ -PHPAPI void session_adapt_url(const char *url, size_t url_len, char **new_url, size_t *new_len) /* {{{ */ +PHPAPI void session_adapt_url(const char *url, size_t url_len, char **new_url, size_t *new_len) { if (APPLY_TRANS_SID && (PS(session_status) == php_session_active)) { *new_url = php_url_scanner_adapt_single_url(url, url_len, PS(session_name), ZSTR_VAL(PS(id)), new_len, 1); } } -/* }}} */ /* ******************************** * Userspace exported functions * ******************************** */ -/* {{{ session_set_cookie_params(array options) - Set session cookie parameters */ PHP_FUNCTION(session_set_cookie_params) { HashTable *options_ht; @@ -1950,9 +1891,7 @@ PHP_FUNCTION(session_set_cookie_params) if (samesite) zend_string_release(samesite); } } -/* }}} */ -/* {{{ Return the session cookie parameters */ PHP_FUNCTION(session_get_cookie_params) { if (zend_parse_parameters_none() == FAILURE) { @@ -1968,9 +1907,8 @@ PHP_FUNCTION(session_get_cookie_params) add_assoc_bool(return_value, "httponly", PS(cookie_httponly)); add_assoc_string(return_value, "samesite", PS(cookie_samesite)); } -/* }}} */ -/* {{{ Return the current session name. If new name is given, the session name is replaced with new name */ +/* Return the current session name. If new name is given, the session name is replaced with new name */ PHP_FUNCTION(session_name) { zend_string *name = NULL; @@ -1998,9 +1936,8 @@ PHP_FUNCTION(session_name) zend_string_release_ex(ini_name, 0); } } -/* }}} */ -/* {{{ Return the current module name used for accessing session data. If newname is given, the module name is replaced with newname */ +/* Return the current module name used for accessing session data. If newname is given, the module name is replaced with newname */ PHP_FUNCTION(session_module_name) { zend_string *name = NULL; @@ -2048,7 +1985,6 @@ PHP_FUNCTION(session_module_name) zend_string_release_ex(ini_name, 0); } } -/* }}} */ static bool can_session_handler_be_changed(void) { if (PS(session_status) == php_session_active) { @@ -2108,7 +2044,6 @@ static inline void set_user_save_handler_ini(void) { SESSION_SET_USER_HANDLER_PROCEDURAL(struct_name, fci); \ } -/* {{{ Sets user-level functions */ PHP_FUNCTION(session_set_save_handler) { /* OOP Version */ @@ -2277,9 +2212,8 @@ PHP_FUNCTION(session_set_save_handler) RETURN_TRUE; } -/* }}} */ -/* {{{ Return the current save path passed to module_name. If newname is given, the save path is replaced with newname */ +/* Return the current save path passed to module_name. If newname is given, the save path is replaced with newname */ PHP_FUNCTION(session_save_path) { zend_string *name = NULL; @@ -2307,9 +2241,8 @@ PHP_FUNCTION(session_save_path) zend_string_release_ex(ini_name, 0); } } -/* }}} */ -/* {{{ Return the current session id. If newid is given, the session id is replaced with newid */ +/* Return the current session id. If newid is given, the session id is replaced with newid */ PHP_FUNCTION(session_id) { zend_string *name = NULL; @@ -2348,9 +2281,8 @@ PHP_FUNCTION(session_id) PS(id) = zend_string_copy(name); } } -/* }}} */ -/* {{{ Update the current session id with a newly generated one. If delete_old_session is set to true, remove the old session. */ +/* Update the current session id with a newly generated one. If delete_old_session is set to true, remove the old session. */ PHP_FUNCTION(session_regenerate_id) { bool del_ses = 0; @@ -2463,9 +2395,8 @@ PHP_FUNCTION(session_regenerate_id) RETURN_TRUE; } -/* }}} */ -/* {{{ Generate new session ID. Intended for user save handlers. */ +/* Generate new session ID. Intended for user save handlers. */ PHP_FUNCTION(session_create_id) { zend_string *prefix = NULL, *new_id; @@ -2519,9 +2450,8 @@ PHP_FUNCTION(session_create_id) } RETVAL_STR(smart_str_extract(&id)); } -/* }}} */ -/* {{{ Return the current cache limiter. If new_cache_limited is given, the current cache_limiter is replaced with new_cache_limiter */ +/* Return the current cache limiter. If new_cache_limited is given, the current cache_limiter is replaced with new_cache_limiter */ PHP_FUNCTION(session_cache_limiter) { zend_string *limiter = NULL; @@ -2549,9 +2479,8 @@ PHP_FUNCTION(session_cache_limiter) zend_string_release_ex(ini_name, 0); } } -/* }}} */ -/* {{{ Return the current cache expire. If new_cache_expire is given, the current cache_expire is replaced with new_cache_expire */ +/* Return the current cache expire. If new_cache_expire is given, the current cache_expire is replaced with new_cache_expire */ PHP_FUNCTION(session_cache_expire) { zend_long expires; @@ -2581,9 +2510,8 @@ PHP_FUNCTION(session_cache_expire) zend_string_release_ex(ini_value, 0); } } -/* }}} */ -/* {{{ Serializes the current setup and returns the serialized representation */ +/* Serializes the current setup and returns the serialized representation */ PHP_FUNCTION(session_encode) { zend_string *enc; @@ -2599,9 +2527,8 @@ PHP_FUNCTION(session_encode) RETURN_STR(enc); } -/* }}} */ -/* {{{ Deserializes data and reinitializes the variables */ +/* Deserializes data and reinitializes the variables */ PHP_FUNCTION(session_decode) { zend_string *str = NULL; @@ -2620,7 +2547,6 @@ PHP_FUNCTION(session_decode) } RETURN_TRUE; } -/* }}} */ static zend_result php_session_start_set_ini(zend_string *varname, zend_string *new_value) { zend_result ret; @@ -2634,7 +2560,6 @@ static zend_result php_session_start_set_ini(zend_string *varname, zend_string * return ret; } -/* {{{ Begin session */ PHP_FUNCTION(session_start) { zval *options = NULL; @@ -2722,9 +2647,7 @@ PHP_FUNCTION(session_start) RETURN_TRUE; } -/* }}} */ -/* {{{ Destroy the current session and all data associated with it */ PHP_FUNCTION(session_destroy) { if (zend_parse_parameters_none() == FAILURE) { @@ -2733,9 +2656,7 @@ PHP_FUNCTION(session_destroy) RETURN_BOOL(php_session_destroy() == SUCCESS); } -/* }}} */ -/* {{{ Unset all registered variables */ PHP_FUNCTION(session_unset) { if (zend_parse_parameters_none() == FAILURE) { @@ -2755,9 +2676,7 @@ PHP_FUNCTION(session_unset) } RETURN_TRUE; } -/* }}} */ -/* {{{ Perform GC and return number of deleted sessions */ PHP_FUNCTION(session_gc) { zend_long num; @@ -2778,10 +2697,8 @@ PHP_FUNCTION(session_gc) RETURN_LONG(num); } -/* }}} */ -/* {{{ Write session data and end session */ PHP_FUNCTION(session_write_close) { if (zend_parse_parameters_none() == FAILURE) { @@ -2794,9 +2711,8 @@ PHP_FUNCTION(session_write_close) php_session_flush(1); RETURN_TRUE; } -/* }}} */ -/* {{{ Abort session and end session. Session data will not be written */ +/* Abort session and end session. Session data will not be written */ PHP_FUNCTION(session_abort) { if (zend_parse_parameters_none() == FAILURE) { @@ -2809,9 +2725,8 @@ PHP_FUNCTION(session_abort) php_session_abort(); RETURN_TRUE; } -/* }}} */ -/* {{{ Reset session data from saved session data */ +/* Reset session data from saved session data */ PHP_FUNCTION(session_reset) { if (zend_parse_parameters_none() == FAILURE) { @@ -2824,9 +2739,7 @@ PHP_FUNCTION(session_reset) php_session_reset(); RETURN_TRUE; } -/* }}} */ -/* {{{ Returns the current session status */ PHP_FUNCTION(session_status) { if (zend_parse_parameters_none() == FAILURE) { @@ -2835,9 +2748,8 @@ PHP_FUNCTION(session_status) RETURN_LONG(PS(session_status)); } -/* }}} */ -/* {{{ Registers session_write_close() as a shutdown function */ +/* Registers session_write_close() as a shutdown function */ PHP_FUNCTION(session_register_shutdown) { php_shutdown_function_entry shutdown_function_entry = { @@ -2869,13 +2781,12 @@ PHP_FUNCTION(session_register_shutdown) php_error_docref(NULL, E_WARNING, "Session shutdown function cannot be registered"); } } -/* }}} */ /* ******************************** * Module Setup and Destruction * ******************************** */ -static zend_result php_rinit_session(bool auto_start) /* {{{ */ +static zend_result php_rinit_session(bool auto_start) { php_rinit_session_globals(); @@ -2909,13 +2820,12 @@ static zend_result php_rinit_session(bool auto_start) /* {{{ */ } return SUCCESS; -} /* }}} */ +} -static PHP_RINIT_FUNCTION(session) /* {{{ */ +static PHP_RINIT_FUNCTION(session) { return php_rinit_session(PS(auto_start)); } -/* }}} */ #define SESSION_FREE_USER_HANDLER(struct_name) \ if (!Z_ISUNDEF(PS(mod_user_names).struct_name)) { \ @@ -2924,7 +2834,7 @@ static PHP_RINIT_FUNCTION(session) /* {{{ */ } -static PHP_RSHUTDOWN_FUNCTION(session) /* {{{ */ +static PHP_RSHUTDOWN_FUNCTION(session) { if (PS(session_status) == php_session_active) { zend_try { @@ -2947,9 +2857,8 @@ static PHP_RSHUTDOWN_FUNCTION(session) /* {{{ */ return SUCCESS; } -/* }}} */ -static PHP_GINIT_FUNCTION(ps) /* {{{ */ +static PHP_GINIT_FUNCTION(ps) { #if defined(COMPILE_DL_SESSION) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); @@ -2995,9 +2904,8 @@ static PHP_GINIT_FUNCTION(ps) /* {{{ */ } php_random_pcgoneseq128xslrr64_seed128(ps_globals->random.state, seed); } -/* }}} */ -static PHP_MINIT_FUNCTION(session) /* {{{ */ +static PHP_MINIT_FUNCTION(session) { zend_register_auto_global(zend_string_init_interned("_SESSION", sizeof("_SESSION") - 1, 1), 0, NULL); @@ -3027,9 +2935,8 @@ static PHP_MINIT_FUNCTION(session) /* {{{ */ return SUCCESS; } -/* }}} */ -static PHP_MSHUTDOWN_FUNCTION(session) /* {{{ */ +static PHP_MSHUTDOWN_FUNCTION(session) { UNREGISTER_INI_ENTRIES(); @@ -3048,9 +2955,8 @@ static PHP_MSHUTDOWN_FUNCTION(session) /* {{{ */ return SUCCESS; } -/* }}} */ -static PHP_MINFO_FUNCTION(session) /* {{{ */ +static PHP_MINFO_FUNCTION(session) { const ps_module **mod; ps_serializer *ser; @@ -3097,19 +3003,17 @@ static PHP_MINFO_FUNCTION(session) /* {{{ */ DISPLAY_INI_ENTRIES(); } -/* }}} */ -static const zend_module_dep session_deps[] = { /* {{{ */ +static const zend_module_dep session_deps[] = { ZEND_MOD_OPTIONAL("spl") ZEND_MOD_END }; -/* }}} */ /* ************************ * Upload hook handling * ************************ */ -static bool early_find_sid_in(zval *dest, int where, php_session_rfc1867_progress *progress) /* {{{ */ +static bool early_find_sid_in(zval *dest, int where, php_session_rfc1867_progress *progress) { zval *ppid; @@ -3125,9 +3029,9 @@ static bool early_find_sid_in(zval *dest, int where, php_session_rfc1867_progres } return 0; -} /* }}} */ +} -static void php_session_rfc1867_early_find_sid(php_session_rfc1867_progress *progress) /* {{{ */ +static void php_session_rfc1867_early_find_sid(php_session_rfc1867_progress *progress) { if (PS(use_cookies)) { @@ -3142,9 +3046,9 @@ static void php_session_rfc1867_early_find_sid(php_session_rfc1867_progress *pro } sapi_module.treat_data(PARSE_GET, NULL, NULL); early_find_sid_in(&progress->sid, TRACK_VARS_GET, progress); -} /* }}} */ +} -static bool php_check_cancel_upload(php_session_rfc1867_progress *progress) /* {{{ */ +static bool php_check_cancel_upload(php_session_rfc1867_progress *progress) { zval *progress_ary, *cancel_upload; @@ -3158,9 +3062,9 @@ static bool php_check_cancel_upload(php_session_rfc1867_progress *progress) /* { return 0; } return Z_TYPE_P(cancel_upload) == IS_TRUE; -} /* }}} */ +} -static void php_session_rfc1867_update(php_session_rfc1867_progress *progress, int force_update) /* {{{ */ +static void php_session_rfc1867_update(php_session_rfc1867_progress *progress, int force_update) { if (!force_update) { if (Z_LVAL_P(progress->post_bytes_processed) < progress->next_update) { @@ -3192,9 +3096,9 @@ static void php_session_rfc1867_update(php_session_rfc1867_progress *progress, i zend_hash_update(Z_ARRVAL_P(sess_var), progress->key.s, &progress->data); } php_session_flush(1); -} /* }}} */ +} -static void php_session_rfc1867_cleanup(php_session_rfc1867_progress *progress) /* {{{ */ +static void php_session_rfc1867_cleanup(php_session_rfc1867_progress *progress) { php_session_initialize(); PS(session_status) = php_session_active; @@ -3204,9 +3108,9 @@ static void php_session_rfc1867_cleanup(php_session_rfc1867_progress *progress) zend_hash_del(Z_ARRVAL_P(sess_var), progress->key.s); } php_session_flush(1); -} /* }}} */ +} -static zend_result php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra) /* {{{ */ +static zend_result php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra) { php_session_rfc1867_progress *progress; zend_result retval = SUCCESS; @@ -3388,8 +3292,7 @@ static zend_result php_session_rfc1867_callback(unsigned int event, void *event_ return FAILURE; } return retval; - -} /* }}} */ +} zend_module_entry session_module_entry = { STANDARD_MODULE_HEADER_EX, diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 1de7ccc6e74e8..3ec45e3078173 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -631,7 +631,9 @@ static zval *sxe_property_get_adr(zend_object *object, zend_string *zname, int f SXE_ITER type; zval member; - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } sxe = php_sxe_fetch_object(object); GET_NODE(sxe, node); @@ -1215,6 +1217,21 @@ static int sxe_objects_compare(zval *object1, zval *object2) /* {{{ */ } /* }}} */ +static const char *sxe_get_object_type_name(xmlXPathObjectType type) +{ + switch (type) { + case XPATH_BOOLEAN: return "bool"; + case XPATH_NUMBER: return "number"; + case XPATH_STRING: return "string"; +#ifdef LIBXML_XPTR_LOCS_ENABLED + case XPATH_POINT: return "point"; + case XPATH_RANGE: return "range"; + case XPATH_LOCATIONSET: return "location set"; +#endif + default: return "undefined"; + } +} + /* {{{ Runs XPath query on the XML data */ PHP_METHOD(SimpleXMLElement, xpath) { @@ -1271,6 +1288,13 @@ PHP_METHOD(SimpleXMLElement, xpath) RETURN_FALSE; } + if (UNEXPECTED(retval->type != XPATH_NODESET)) { + php_error_docref(NULL, E_WARNING, "XPath expression must return a node set, %s returned", + sxe_get_object_type_name(retval->type)); + xmlXPathFreeObject(retval); + RETURN_FALSE; + } + result = retval->nodesetval; if (result != NULL) { diff --git a/ext/simplexml/tests/008.phpt b/ext/simplexml/tests/008.phpt index c946c36dafe63..dea6f98eacfcc 100644 --- a/ext/simplexml/tests/008.phpt +++ b/ext/simplexml/tests/008.phpt @@ -39,8 +39,9 @@ array(1) { } } } -array(0) { -} -Warning: SimpleXMLElement::xpath(): Invalid expression in %s on line %d%A +Warning: SimpleXMLElement::xpath(): XPath expression must return a node set, number returned in %s on line %d +bool(false) + +Warning: SimpleXMLElement::xpath(): Invalid expression in %s on line %d bool(false) diff --git a/ext/simplexml/tests/bug51615.phpt b/ext/simplexml/tests/bug51615.phpt index b0ac921fead2a..7245434ff5578 100644 --- a/ext/simplexml/tests/bug51615.phpt +++ b/ext/simplexml/tests/bug51615.phpt @@ -7,7 +7,7 @@ dom loadHTML('xx'); +$dom->loadHTML('xx', LIBXML_NOERROR); $html = simplexml_import_dom($dom); var_dump($html->body->span); @@ -18,15 +18,12 @@ foreach ($html->body->span as $obj) { ?> --EXPECTF-- -Warning: DOMDocument::loadHTML(): error parsing attribute name in Entity, line: 1 in %s on line %d - -Warning: DOMDocument::loadHTML(): error parsing attribute name in Entity, line: 1 in %s on line %d object(SimpleXMLElement)#%d (3) { ["@attributes"]=> array(2) { ["title"]=> string(0) "" - ["y"]=> + [%r("y"{1,2})%r]=> string(0) "" } [0]=> diff --git a/ext/simplexml/tests/gh12231.phpt b/ext/simplexml/tests/gh12231.phpt new file mode 100644 index 0000000000000..efacd92b76f95 --- /dev/null +++ b/ext/simplexml/tests/gh12231.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-12231 (SimpleXML xpath should warn when returning other return types than node lists) +--EXTENSIONS-- +simplexml +--FILE-- +"; +$sxe = simplexml_load_string($xml); + +var_dump($sxe->xpath("count(//foo)")); +var_dump($sxe->xpath("string(//foo)")); +var_dump($sxe->xpath("boolean(//foo)")); +var_dump(count($sxe->xpath("//foo"))); + +?> +--EXPECTF-- +Warning: SimpleXMLElement::xpath(): XPath expression must return a node set, number returned in %s on line %d +bool(false) + +Warning: SimpleXMLElement::xpath(): XPath expression must return a node set, string returned in %s on line %d +bool(false) + +Warning: SimpleXMLElement::xpath(): XPath expression must return a node set, bool returned in %s on line %d +bool(false) +int(2) diff --git a/ext/simplexml/tests/gh18304.phpt b/ext/simplexml/tests/gh18304.phpt new file mode 100644 index 0000000000000..c6b0f76bd04e2 --- /dev/null +++ b/ext/simplexml/tests/gh18304.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault) +--CREDITS-- +orose-assetgo +--EXTENSIONS-- +simplexml +--FILE-- +'); +$field = 'abc'; +$sxe->$field .= 'hello'; +var_dump($sxe->$field); +?> +--EXPECTF-- +object(SimpleXMLElement)#%d (1) { + [0]=> + string(5) "hello" +} diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c index 33c8e58acdd1d..6cede307ac834 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -1921,7 +1921,9 @@ static zval *php_snmp_get_property_ptr_ptr(zend_object *object, zend_string *nam return zend_std_get_property_ptr_ptr(object, name, type, cache_slot); } - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } return NULL; } diff --git a/ext/snmp/tests/gh18304.phpt b/ext/snmp/tests/gh18304.phpt new file mode 100644 index 0000000000000..2faf503ac1a58 --- /dev/null +++ b/ext/snmp/tests/gh18304.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault) +--CREDITS-- +orose-assetgo +--EXTENSIONS-- +snmp +--FILE-- +$field++; +var_dump($snmp->$field); +?> +--EXPECT-- +int(1) diff --git a/ext/soap/php_packet_soap.c b/ext/soap/php_packet_soap.c index 32c40116d25c6..fddb6b63874d9 100644 --- a/ext/soap/php_packet_soap.c +++ b/ext/soap/php_packet_soap.c @@ -192,6 +192,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio if (tmp != NULL && tmp->children != NULL) { zval zv; master_to_zval(&zv, get_conversion(IS_STRING), tmp); + convert_to_string(&zv) faultstring = Z_STR(zv); } @@ -199,6 +200,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio if (tmp != NULL && tmp->children != NULL) { zval zv; master_to_zval(&zv, get_conversion(IS_STRING), tmp); + convert_to_string(&zv) faultactor = Z_STR(zv); } @@ -222,6 +224,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio if (tmp != NULL && tmp->children != NULL) { zval zv; master_to_zval(&zv, get_conversion(IS_STRING), tmp); + convert_to_string(&zv) faultstring = Z_STR(zv); } } diff --git a/ext/soap/tests/bugs/bug66049.phpt b/ext/soap/tests/bugs/bug66049.phpt new file mode 100644 index 0000000000000..e48845a8a142b --- /dev/null +++ b/ext/soap/tests/bugs/bug66049.phpt @@ -0,0 +1,48 @@ +--TEST-- +Fix #66049 Typemap can break parsing in parse_packet_soap leading to a segfault +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- + + + + SOAP-ENV:Servernot present + '; + return $res; + } +} + +try { + $client=new TestSoapClient(null, [ + 'uri' => 'test://', + 'location' => 'test://', + 'typemap' => [[ + "type_ns" => "http://www.w3.org/2001/XMLSchema", + "type_name" => "string", + "from_xml" => "soap_string_from_xml" + ]]]); + $client->Mist(""); +} catch (SoapFault $e) { + var_dump($e->faultstring); + var_dump($e->faultcode); +} +?> +Done +--EXPECT-- +soap_string_from_xml +string(3) "2.3" +string(15) "SOAP-ENV:Server" +Done diff --git a/ext/sockets/conversions.c b/ext/sockets/conversions.c index dd3b018c98d72..1f34e6601d4dc 100644 --- a/ext/sockets/conversions.c +++ b/ext/sockets/conversions.c @@ -1024,6 +1024,7 @@ static void to_zval_read_control_array(const char *msghdr_c, zval *zv, res_conte uint32_t i = 1; array_init(zv); + zend_hash_real_init_packed(Z_ARRVAL_P(zv)); for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL && !ctx->err.has_error; diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 68674120892b6..2d8b55c6b97ba 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -1973,6 +1973,7 @@ PHP_FUNCTION(socket_get_option) size_t arrlen = optlen / sizeof(struct fil_info); array_init_size(return_value, arrlen); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for (i = 0; i < arrlen; i++) { add_index_string(return_value, i, fi[i].fi_name); @@ -2373,7 +2374,7 @@ PHP_FUNCTION(socket_create_pair) RETURN_FALSE; } - fds_array_zval = zend_try_array_init(fds_array_zval); + fds_array_zval = zend_try_array_init_size(fds_array_zval, 2); if (!fds_array_zval) { zval_ptr_dtor(&retval[0]); zval_ptr_dtor(&retval[1]); @@ -2776,6 +2777,7 @@ PHP_FUNCTION(socket_addrinfo_lookup) } array_init(return_value); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family != AF_UNSPEC) { diff --git a/ext/sockets/sockets.stub.php b/ext/sockets/sockets.stub.php index 4d6200fcd1ffe..d647f46b80dca 100644 --- a/ext/sockets/sockets.stub.php +++ b/ext/sockets/sockets.stub.php @@ -454,6 +454,13 @@ */ const SO_EXCLBIND = UNKNOWN; #endif +#ifdef SO_BUSY_POLL +/** + * @var int + * @cvalue SO_BUSY_POLL + */ +const SO_BUSY_POLL = UNKNOWN; +#endif #ifdef SKF_AD_OFF /** * @var int diff --git a/ext/sockets/sockets_arginfo.h b/ext/sockets/sockets_arginfo.h index 4a90b4d789feb..45714fb285174 100644 --- a/ext/sockets/sockets_arginfo.h +++ b/ext/sockets/sockets_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: aac197335037777d31d83d4a4040bbfcd0c55813 */ + * Stub hash: 42d486d2666d23569e70860e2b1ef203161792b3 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_socket_select, 0, 4, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(1, read, IS_ARRAY, 1) @@ -476,6 +476,9 @@ static void register_sockets_symbols(int module_number) #if defined(SO_EXCLBIND) REGISTER_LONG_CONSTANT("SO_EXCLBIND", SO_EXCLBIND, CONST_PERSISTENT); #endif +#if defined(SO_BUSY_POLL) + REGISTER_LONG_CONSTANT("SO_BUSY_POLL", SO_BUSY_POLL, CONST_PERSISTENT); +#endif #if defined(SKF_AD_OFF) REGISTER_LONG_CONSTANT("SKF_AD_OFF", SKF_AD_OFF, CONST_PERSISTENT); #endif diff --git a/ext/sockets/tests/socket_export_stream-4-win.phpt b/ext/sockets/tests/socket_export_stream-4-win.phpt index 9eb2b901e1c65..57c7e7a9aeed2 100644 --- a/ext/sockets/tests/socket_export_stream-4-win.phpt +++ b/ext/sockets/tests/socket_export_stream-4-win.phpt @@ -92,7 +92,7 @@ stream_set_blocking 1 close stream -stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource +stream_set_blocking TypeError: stream_set_blocking(): Argument #1 ($stream) must be an open stream resource socket_set_block Warning: socket_set_block(): unable to set blocking mode [%d]: An operation was attempted on something that is not a socket in %s on line %d @@ -103,7 +103,7 @@ Warning: socket_get_option(): Unable to retrieve socket option [%d]: An operatio close socket -stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource +stream_set_blocking TypeError: stream_set_blocking(): Argument #1 ($stream) must be an open stream resource socket_set_block Error: socket_set_block(): Argument #1 ($socket) has already been closed diff --git a/ext/sockets/tests/socket_export_stream-4.phpt b/ext/sockets/tests/socket_export_stream-4.phpt index b8b6c954099c7..512a62379e98c 100644 --- a/ext/sockets/tests/socket_export_stream-4.phpt +++ b/ext/sockets/tests/socket_export_stream-4.phpt @@ -94,7 +94,7 @@ stream_set_blocking 1 close stream -stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource +stream_set_blocking TypeError: stream_set_blocking(): Argument #1 ($stream) must be an open stream resource socket_set_block Warning: socket_set_block(): unable to set blocking mode [%d]: %s in %s on line %d @@ -105,7 +105,7 @@ Warning: socket_get_option(): Unable to retrieve socket option [%d]: %s in %s on close socket -stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource +stream_set_blocking TypeError: stream_set_blocking(): Argument #1 ($stream) must be an open stream resource socket_set_block Error: socket_set_block(): Argument #1 ($socket) has already been closed diff --git a/ext/sockets/tests/socket_import_stream-4-win.phpt b/ext/sockets/tests/socket_import_stream-4-win.phpt index a005347069ed3..ab09f43d92075 100644 --- a/ext/sockets/tests/socket_import_stream-4-win.phpt +++ b/ext/sockets/tests/socket_import_stream-4-win.phpt @@ -87,7 +87,7 @@ stream_set_blocking 1 close stream -stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource +stream_set_blocking TypeError: stream_set_blocking(): Argument #1 ($stream) must be an open stream resource socket_set_block Warning: socket_set_block(): unable to set blocking mode [10038]: %s in %ssocket_import_stream-4-win.php on line %d @@ -98,7 +98,7 @@ Warning: socket_get_option(): Unable to retrieve socket option [10038]: %s in %s close socket -stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource +stream_set_blocking TypeError: stream_set_blocking(): Argument #1 ($stream) must be an open stream resource socket_set_block Error: socket_set_block(): Argument #1 ($socket) has already been closed diff --git a/ext/sockets/tests/socket_import_stream-4.phpt b/ext/sockets/tests/socket_import_stream-4.phpt index c898d614bcff5..25e425961f613 100644 --- a/ext/sockets/tests/socket_import_stream-4.phpt +++ b/ext/sockets/tests/socket_import_stream-4.phpt @@ -89,7 +89,7 @@ stream_set_blocking 1 close stream -stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource +stream_set_blocking TypeError: stream_set_blocking(): Argument #1 ($stream) must be an open stream resource socket_set_block Warning: socket_set_block(): unable to set blocking mode [%d]: %s in %s on line %d @@ -100,7 +100,7 @@ Warning: socket_get_option(): Unable to retrieve socket option [%d]: %s in %s on close socket -stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource +stream_set_blocking TypeError: stream_set_blocking(): Argument #1 ($stream) must be an open stream resource socket_set_block Error: socket_set_block(): Argument #1 ($socket) has already been closed diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 3e386254b7e43..b950330061920 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -665,12 +665,14 @@ static bool spl_array_has_dimension_ex(bool check_inherited, zend_object *object } } + /* empty() check the value is not falsy, isset() only check it is not null */ + bool result = check_empty ? zend_is_true(value) : Z_TYPE_P(value) != IS_NULL; + if (value == &rv) { zval_ptr_dtor(&rv); } - /* empty() check the value is not falsy, isset() only check it is not null */ - return check_empty ? zend_is_true(value) : Z_TYPE_P(value) != IS_NULL; + return result; } /* }}} */ static int spl_array_has_dimension(zend_object *object, zval *offset, int check_empty) /* {{{ */ @@ -861,7 +863,9 @@ static zval *spl_array_get_property_ptr_ptr(zend_object *object, zend_string *na if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 && !zend_std_has_property(object, name, ZEND_PROPERTY_EXISTS, NULL)) { - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } /* If object has offsetGet() overridden, then fallback to read_property, * which will call offsetGet(). */ diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 461bdc1e901ec..751000fe63004 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -1599,12 +1599,12 @@ PHP_METHOD(GlobIterator, count) RETURN_THROWS(); } - /* The spl_filesystem_object_get_method_check() function is called prior to calling this function. - * Therefore, the directory entry cannot be NULL. However, if it is not NULL, then it must be a glob iterator - * by construction. */ - ZEND_ASSERT(spl_intern_is_glob(intern)); - - RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL)); + if (EXPECTED(spl_intern_is_glob(intern))) { + RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL)); + } else { + /* This can happen by avoiding constructors in specially-crafted code. */ + zend_throw_error(NULL, "GlobIterator is not initialized"); + } } /* }}} */ #endif /* HAVE_GLOB */ diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index b919501c0dd25..dc32045ba0ff9 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -212,12 +212,15 @@ static void spl_fixedarray_resize(spl_fixedarray *array, zend_long size) static HashTable* spl_fixedarray_object_get_gc(zend_object *obj, zval **table, int *n) { spl_fixedarray_object *intern = spl_fixed_array_from_obj(obj); - HashTable *ht = zend_std_get_properties(obj); *table = intern->array.elements; *n = (int)intern->array.size; - return ht; + if (obj->properties == NULL && obj->ce->default_properties_count == 0) { + return NULL; + } else { + return zend_std_get_properties(obj); + } } static HashTable* spl_fixedarray_object_get_properties_for(zend_object *obj, zend_prop_purpose purpose) @@ -275,7 +278,6 @@ static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, z { spl_fixedarray_object *intern; zend_class_entry *parent = class_type; - bool inherited = false; intern = zend_object_alloc(sizeof(spl_fixedarray_object), parent); @@ -287,21 +289,10 @@ static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, z spl_fixedarray_copy_ctor(&intern->array, &other->array); } - while (parent) { - if (parent == spl_ce_SplFixedArray) { - break; - } - - parent = parent->parent; - inherited = true; - } - - ZEND_ASSERT(parent); - - if (UNEXPECTED(inherited)) { + if (UNEXPECTED(class_type != spl_ce_SplFixedArray)) { /* Find count() method */ zend_function *fptr_count = zend_hash_find_ptr(&class_type->function_table, ZSTR_KNOWN(ZEND_STR_COUNT)); - if (fptr_count->common.scope == parent) { + if (fptr_count->common.scope == spl_ce_SplFixedArray) { fptr_count = NULL; } intern->fptr_count = fptr_count; @@ -324,14 +315,14 @@ static zend_object *spl_fixedarray_object_clone(zend_object *old_object) return new_object; } -static zend_long spl_offset_convert_to_long(zval *offset) /* {{{ */ +static zend_never_inline zend_ulong spl_offset_convert_to_ulong_slow(const zval *offset) /* {{{ */ { try_again: switch (Z_TYPE_P(offset)) { case IS_STRING: { zend_ulong index; if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), index)) { - return (zend_long) index; + return index; } break; } @@ -356,23 +347,35 @@ static zend_long spl_offset_convert_to_long(zval *offset) /* {{{ */ return 0; } -static zval *spl_fixedarray_object_read_dimension_helper(spl_fixedarray_object *intern, zval *offset) +/* Returned index is an unsigned number such that we don't have to do a negative check. + * Negative numbers will be mapped at indices larger than ZEND_ULONG_MAX, + * which is beyond the maximum length. */ +static zend_always_inline zend_ulong spl_offset_convert_to_ulong(const zval *offset) { - zend_long index; + if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { + /* Allow skipping exception check at call-site. */ + ZEND_ASSERT(!EG(exception)); + return Z_LVAL_P(offset); + } else { + return spl_offset_convert_to_ulong_slow(offset); + } +} +static zval *spl_fixedarray_object_read_dimension_helper(spl_fixedarray_object *intern, zval *offset) +{ /* we have to return NULL on error here to avoid memleak because of * ZE duplicating uninitialized_zval_ptr */ - if (!offset) { + if (UNEXPECTED(!offset)) { zend_throw_error(NULL, "[] operator not supported for SplFixedArray"); return NULL; } - index = spl_offset_convert_to_long(offset); - if (EG(exception)) { + zend_ulong index = spl_offset_convert_to_ulong(offset); + if (UNEXPECTED(EG(exception))) { return NULL; } - if (index < 0 || index >= intern->array.size) { + if (UNEXPECTED(index >= intern->array.size)) { zend_throw_exception(spl_ce_OutOfBoundsException, "Index invalid or out of range", 0); return NULL; } else { @@ -407,29 +410,26 @@ static zval *spl_fixedarray_object_read_dimension(zend_object *object, zval *off static void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *intern, zval *offset, zval *value) { - zend_long index; - - if (!offset) { + if (UNEXPECTED(!offset)) { /* '$array[] = value' syntax is not supported */ zend_throw_error(NULL, "[] operator not supported for SplFixedArray"); return; } - index = spl_offset_convert_to_long(offset); - if (EG(exception)) { + zend_ulong index = spl_offset_convert_to_ulong(offset); + if (UNEXPECTED(EG(exception))) { return; } - if (index < 0 || index >= intern->array.size) { + if (UNEXPECTED(index >= intern->array.size)) { zend_throw_exception(spl_ce_OutOfBoundsException, "Index invalid or out of range", 0); - return; } else { /* Fix #81429 */ zval *ptr = &(intern->array.elements[index]); - zval tmp; - ZVAL_COPY_VALUE(&tmp, ptr); - ZVAL_COPY_DEREF(ptr, value); - zval_ptr_dtor(&tmp); + /* This should be guaranteed by the VM handler or argument parsing. */ + ZEND_ASSERT(Z_TYPE_P(value) != IS_REFERENCE); + Z_TRY_ADDREF_P(value); + zend_safe_assign_to_variable_noref(ptr, value); } } @@ -452,21 +452,17 @@ static void spl_fixedarray_object_write_dimension(zend_object *object, zval *off static void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *intern, zval *offset) { - zend_long index; - - index = spl_offset_convert_to_long(offset); - if (EG(exception)) { + zend_ulong index = spl_offset_convert_to_ulong(offset); + if (UNEXPECTED(EG(exception))) { return; } - if (index < 0 || index >= intern->array.size) { + if (UNEXPECTED(index >= intern->array.size)) { zend_throw_exception(spl_ce_OutOfBoundsException, "Index invalid or out of range", 0); - return; } else { - zval garbage; - ZVAL_COPY_VALUE(&garbage, &intern->array.elements[index]); - ZVAL_NULL(&intern->array.elements[index]); - zval_ptr_dtor(&garbage); + zval null = {0}; + ZVAL_NULL(&null); + zend_safe_assign_to_variable_noref(&intern->array.elements[index], &null); } } @@ -483,14 +479,12 @@ static void spl_fixedarray_object_unset_dimension(zend_object *object, zval *off static bool spl_fixedarray_object_has_dimension_helper(spl_fixedarray_object *intern, zval *offset, bool check_empty) { - zend_long index; - - index = spl_offset_convert_to_long(offset); - if (EG(exception)) { + zend_ulong index = spl_offset_convert_to_ulong(offset); + if (UNEXPECTED(EG(exception))) { return false; } - if (index < 0 || index >= intern->array.size) { + if (index >= intern->array.size) { return false; } @@ -691,11 +685,16 @@ PHP_METHOD(SplFixedArray, toArray) intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); if (!spl_fixedarray_empty(&intern->array)) { - array_init(return_value); - for (zend_long i = 0; i < intern->array.size; i++) { - zend_hash_index_update(Z_ARRVAL_P(return_value), i, &intern->array.elements[i]); - Z_TRY_ADDREF(intern->array.elements[i]); - } + array_init_size(return_value, intern->array.size); + HashTable *ht = Z_ARRVAL_P(return_value); + zend_hash_real_init_packed(ht); + + ZEND_HASH_FILL_PACKED(ht) { + for (zend_long i = 0; i < intern->array.size; i++) { + ZEND_HASH_FILL_ADD(&intern->array.elements[i]); + Z_TRY_ADDREF(intern->array.elements[i]); + } + } ZEND_HASH_FILL_END(); } else { RETURN_EMPTY_ARRAY(); } @@ -721,22 +720,29 @@ PHP_METHOD(SplFixedArray, fromArray) zend_ulong num_index, max_index = 0; zend_long tmp; - ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(data), num_index, str_index) { - if (str_index != NULL || (zend_long)num_index < 0) { - zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "array must contain only positive integer keys"); + if (HT_IS_PACKED(Z_ARRVAL_P(data))) { + /* If there are no holes, then nNumUsed is the number of elements. + * If there are holes, then nNumUsed is the index of the last element. */ + tmp = Z_ARRVAL_P(data)->nNumUsed; + } else { + ZEND_HASH_MAP_FOREACH_KEY(Z_ARRVAL_P(data), num_index, str_index) { + if (str_index != NULL || (zend_long)num_index < 0) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "array must contain only positive integer keys"); + RETURN_THROWS(); + } + + if (num_index > max_index) { + max_index = num_index; + } + } ZEND_HASH_FOREACH_END(); + + tmp = max_index + 1; + if (tmp <= 0) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "integer overflow detected"); RETURN_THROWS(); } - - if (num_index > max_index) { - max_index = num_index; - } - } ZEND_HASH_FOREACH_END(); - - tmp = max_index + 1; - if (tmp <= 0) { - zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "integer overflow detected"); - RETURN_THROWS(); } + spl_fixedarray_init(&array, tmp); ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(data), num_index, element) { @@ -872,18 +878,6 @@ PHP_METHOD(SplFixedArray, getIterator) zend_create_internal_iterator_zval(return_value, ZEND_THIS); } -PHP_METHOD(SplFixedArray, jsonSerialize) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); - array_init_size(return_value, intern->array.size); - for (zend_long i = 0; i < intern->array.size; i++) { - zend_hash_next_index_insert_new(Z_ARR_P(return_value), &intern->array.elements[i]); - Z_TRY_ADDREF(intern->array.elements[i]); - } -} - static void spl_fixedarray_it_dtor(zend_object_iterator *iter) { zval_ptr_dtor(&iter->data); diff --git a/ext/spl/spl_fixedarray.stub.php b/ext/spl/spl_fixedarray.stub.php index a5a239ab4d69c..aa8aa5dbed188 100644 --- a/ext/spl/spl_fixedarray.stub.php +++ b/ext/spl/spl_fixedarray.stub.php @@ -55,5 +55,8 @@ public function offsetUnset($index): void {} public function getIterator(): Iterator {} + /** + * @implementation-alias SplFixedArray::toArray + */ public function jsonSerialize(): array {} } diff --git a/ext/spl/spl_fixedarray_arginfo.h b/ext/spl/spl_fixedarray_arginfo.h index 5d83183d91b81..c2ff9a77ac40f 100644 --- a/ext/spl/spl_fixedarray_arginfo.h +++ b/ext/spl/spl_fixedarray_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c01c9337e58601ff9e6c85072a62f68cc7fec9ba */ + * Stub hash: 0c838fed60b29671fe04e63315ab662d8cb16f0c */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SplFixedArray___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, size, IS_LONG, 0, "0") @@ -68,7 +68,6 @@ ZEND_METHOD(SplFixedArray, offsetGet); ZEND_METHOD(SplFixedArray, offsetSet); ZEND_METHOD(SplFixedArray, offsetUnset); ZEND_METHOD(SplFixedArray, getIterator); -ZEND_METHOD(SplFixedArray, jsonSerialize); static const zend_function_entry class_SplFixedArray_methods[] = { ZEND_ME(SplFixedArray, __construct, arginfo_class_SplFixedArray___construct, ZEND_ACC_PUBLIC) @@ -85,7 +84,7 @@ static const zend_function_entry class_SplFixedArray_methods[] = { ZEND_ME(SplFixedArray, offsetSet, arginfo_class_SplFixedArray_offsetSet, ZEND_ACC_PUBLIC) ZEND_ME(SplFixedArray, offsetUnset, arginfo_class_SplFixedArray_offsetUnset, ZEND_ACC_PUBLIC) ZEND_ME(SplFixedArray, getIterator, arginfo_class_SplFixedArray_getIterator, ZEND_ACC_PUBLIC) - ZEND_ME(SplFixedArray, jsonSerialize, arginfo_class_SplFixedArray_jsonSerialize, ZEND_ACC_PUBLIC) + ZEND_RAW_FENTRY("jsonSerialize", zim_SplFixedArray_toArray, arginfo_class_SplFixedArray_jsonSerialize, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_FE_END }; diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index af9c598f08b08..e6e6786c1c23b 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -335,12 +335,10 @@ static inline HashTable* spl_object_storage_debug_info(zend_object *obj) /* {{{ ZEND_HASH_FOREACH_PTR(&intern->storage, element) { array_init(&tmp); - /* Incrementing the refcount of obj and inf would confuse the garbage collector. - * Prefer to null the destructor */ - Z_ARRVAL_P(&tmp)->pDestructor = NULL; zval obj; - ZVAL_OBJ(&obj, element->obj); + ZVAL_OBJ_COPY(&obj, element->obj); add_assoc_zval_ex(&tmp, "obj", sizeof("obj") - 1, &obj); + Z_TRY_ADDREF(element->inf); add_assoc_zval_ex(&tmp, "inf", sizeof("inf") - 1, &element->inf); zend_hash_next_index_insert(Z_ARRVAL(storage), &tmp); } ZEND_HASH_FOREACH_END(); diff --git a/ext/spl/tests/GlobIterator_constructor_count.phpt b/ext/spl/tests/GlobIterator_constructor_count.phpt new file mode 100644 index 0000000000000..5f96be6219d62 --- /dev/null +++ b/ext/spl/tests/GlobIterator_constructor_count.phpt @@ -0,0 +1,14 @@ +--TEST-- +GlobIterator without constructor breaks count() +--FILE-- +newInstanceWithoutConstructor(); +try { + count($in); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +GlobIterator is not initialized diff --git a/ext/spl/tests/bug81691.phpt b/ext/spl/tests/bug81691.phpt index 597e37a9c8218..5ae5dd6b08fda 100644 --- a/ext/spl/tests/bug81691.phpt +++ b/ext/spl/tests/bug81691.phpt @@ -10,6 +10,6 @@ var_dump($obj->fgets()); ?> --EXPECTF-- -Warning: fclose(): %d is not a valid stream resource in %s on line %d +Warning: fclose(): cannot close the provided stream, as it must not be manually closed in %s on line %d string(6) " 1]; + +$object = new Crap($values); + +var_dump(empty($object['qux'])); +?> +--EXPECT-- +bool(false) diff --git a/ext/spl/tests/gh18304.phpt b/ext/spl/tests/gh18304.phpt new file mode 100644 index 0000000000000..d93ee3534d0d4 --- /dev/null +++ b/ext/spl/tests/gh18304.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault) +--CREDITS-- +orose-assetgo +--FILE-- + 1]); +$ao->setFlags(ArrayObject::ARRAY_AS_PROPS); +$field = 'abc'; +$ao->$field++; +var_dump($ao->$field); +?> +--EXPECT-- +int(2) diff --git a/ext/spl/tests/gh18322.phpt b/ext/spl/tests/gh18322.phpt new file mode 100644 index 0000000000000..e70cbd0d37dd5 --- /dev/null +++ b/ext/spl/tests/gh18322.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-18322 (SplObjectStorage debug handler mismanages memory) +--FILE-- +__debugInfo(); +$tmp2 = $tmp[array_key_first($tmp)]; +unset($tmp); // Drop $tmp2 RC to 1 +$tmp2[0]['obj'] = new stdClass; +var_dump($tmp2); + +?> +--EXPECT-- +array(1) { + [0]=> + array(2) { + ["obj"]=> + object(stdClass)#3 (0) { + } + ["inf"]=> + int(1) + } +} diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 068f437c6984b..1396e693d9955 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -701,9 +701,10 @@ PHP_METHOD(SQLite3, querySingle) if (!entire_row) { sqlite_value_to_zval(stmt, 0, return_value); } else { - int i = 0; - array_init(return_value); - for (i = 0; i < sqlite3_data_count(stmt); i++) { + int i = 0, count = sqlite3_data_count(stmt); + + array_init_size(return_value, count); + for (i = 0; i < count; i++) { zval data; sqlite_value_to_zval(stmt, i, &data); add_assoc_zval(return_value, (char*)sqlite3_column_name(stmt, i), &data); diff --git a/ext/standard/array.c b/ext/standard/array.c index 8462492651310..cabb43d8a914c 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -632,6 +632,18 @@ PHPAPI zend_long php_count_recursive(HashTable *ht) /* {{{ */ } /* }}} */ +/* Consumes `zv` */ +static zend_always_inline zend_long php_get_long(zval *zv) +{ + if (EXPECTED(Z_TYPE_P(zv) == IS_LONG)) { + return Z_LVAL_P(zv); + } else { + zend_long ret = zval_get_long_func(zv, false); + zval_ptr_dtor(zv); + return ret; + } +} + /* {{{ Count the number of elements in a variable (usually an array) */ PHP_FUNCTION(count) { @@ -677,8 +689,7 @@ PHP_FUNCTION(count) zend_function *count_fn = zend_hash_find_ptr(&zobj->ce->function_table, ZSTR_KNOWN(ZEND_STR_COUNT)); zend_call_known_instance_method_with_0_params(count_fn, zobj, &retval); if (Z_TYPE(retval) != IS_UNDEF) { - RETVAL_LONG(zval_get_long(&retval)); - zval_ptr_dtor(&retval); + RETVAL_LONG(php_get_long(&retval)); } return; } @@ -811,20 +822,14 @@ static inline int php_array_user_compare_unstable(Bucket *f, Bucket *s) /* {{{ * { zval args[2]; zval retval; - bool call_failed; - ZVAL_COPY(&args[0], &f->val); - ZVAL_COPY(&args[1], &s->val); + ZVAL_COPY_VALUE(&args[0], &f->val); + ZVAL_COPY_VALUE(&args[1], &s->val); BG(user_compare_fci).param_count = 2; BG(user_compare_fci).params = args; BG(user_compare_fci).retval = &retval; - call_failed = zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE || Z_TYPE(retval) == IS_UNDEF; - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[0]); - if (UNEXPECTED(call_failed)) { - return 0; - } + zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)); if (UNEXPECTED(Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE)) { if (!ARRAYG(compare_deprecation_thrown)) { @@ -836,23 +841,16 @@ static inline int php_array_user_compare_unstable(Bucket *f, Bucket *s) /* {{{ * if (Z_TYPE(retval) == IS_FALSE) { /* Retry with swapped operands. */ - ZVAL_COPY(&args[0], &s->val); - ZVAL_COPY(&args[1], &f->val); - call_failed = zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE || Z_TYPE(retval) == IS_UNDEF; - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[0]); - if (call_failed) { - return 0; - } + ZVAL_COPY_VALUE(&args[0], &s->val); + ZVAL_COPY_VALUE(&args[1], &f->val); + zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)); - zend_long ret = zval_get_long(&retval); - zval_ptr_dtor(&retval); + zend_long ret = php_get_long(&retval); return -ZEND_NORMALIZE_BOOL(ret); } } - zend_long ret = zval_get_long(&retval); - zval_ptr_dtor(&retval); + zend_long ret = php_get_long(&retval); return ZEND_NORMALIZE_BOOL(ret); } /* }}} */ @@ -929,28 +927,22 @@ static inline int php_array_user_key_compare_unstable(Bucket *f, Bucket *s) /* { { zval args[2]; zval retval; - bool call_failed; if (f->key == NULL) { ZVAL_LONG(&args[0], f->h); } else { - ZVAL_STR_COPY(&args[0], f->key); + ZVAL_STR(&args[0], f->key); } if (s->key == NULL) { ZVAL_LONG(&args[1], s->h); } else { - ZVAL_STR_COPY(&args[1], s->key); + ZVAL_STR(&args[1], s->key); } BG(user_compare_fci).param_count = 2; BG(user_compare_fci).params = args; BG(user_compare_fci).retval = &retval; - call_failed = zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE || Z_TYPE(retval) == IS_UNDEF; - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[0]); - if (UNEXPECTED(call_failed)) { - return 0; - } + zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)); if (UNEXPECTED(Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE)) { if (!ARRAYG(compare_deprecation_thrown)) { @@ -965,29 +957,22 @@ static inline int php_array_user_key_compare_unstable(Bucket *f, Bucket *s) /* { if (s->key == NULL) { ZVAL_LONG(&args[0], s->h); } else { - ZVAL_STR_COPY(&args[0], s->key); + ZVAL_STR(&args[0], s->key); } if (f->key == NULL) { ZVAL_LONG(&args[1], f->h); } else { - ZVAL_STR_COPY(&args[1], f->key); + ZVAL_STR(&args[1], f->key); } - call_failed = zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE || Z_TYPE(retval) == IS_UNDEF; - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[0]); - if (call_failed) { - return 0; - } + zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)); - zend_long ret = zval_get_long(&retval); - zval_ptr_dtor(&retval); + zend_long ret = php_get_long(&retval); return -ZEND_NORMALIZE_BOOL(ret); } } - zend_long result = zval_get_long(&retval); - zval_ptr_dtor(&retval); + zend_long result = php_get_long(&retval); return ZEND_NORMALIZE_BOOL(result); } /* }}} */ @@ -1972,8 +1957,10 @@ static zend_long php_extract_ref_overwrite(zend_array *arr, zend_array *symbol_t } else { ZVAL_MAKE_REF_EX(entry, 2); } - zval_ptr_dtor(orig_var); + zval garbage; + ZVAL_COPY_VALUE(&garbage, orig_var); ZVAL_REF(orig_var, Z_REF_P(entry)); + zval_ptr_dtor(&garbage); } else { if (Z_ISREF_P(entry)) { Z_ADDREF_P(entry); @@ -3517,8 +3504,7 @@ static void php_splice(HashTable *in_hash, zend_long offset, zend_long length, H PHP_FUNCTION(array_push) { zval *args, /* Function arguments array */ - *stack, /* Input array */ - new_var; /* Variable to be pushed */ + *stack; /* Input array */ uint32_t argc; /* Number of function arguments */ @@ -3529,10 +3515,10 @@ PHP_FUNCTION(array_push) /* For each subsequent argument, make it a reference, increase refcount, and add it to the end of the array */ for (uint32_t i = 0; i < argc; i++) { - ZVAL_COPY(&new_var, &args[i]); + Z_TRY_ADDREF(args[i]); - if (zend_hash_next_index_insert(Z_ARRVAL_P(stack), &new_var) == NULL) { - Z_TRY_DELREF(new_var); + if (zend_hash_next_index_insert(Z_ARRVAL_P(stack), &args[i]) == NULL) { + Z_TRY_DELREF(args[i]); zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied"); RETURN_THROWS(); } @@ -5065,13 +5051,9 @@ static int zval_user_compare(zval *a, zval *b) /* {{{ */ BG(user_compare_fci).params = args; BG(user_compare_fci).retval = &retval; - if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { - zend_long ret = zval_get_long(&retval); - zval_ptr_dtor(&retval); - return ZEND_NORMALIZE_BOOL(ret); - } else { - return 0; - } + zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)); + zend_long ret = php_get_long(&retval); + return ZEND_NORMALIZE_BOOL(ret); } /* }}} */ @@ -6456,9 +6438,8 @@ PHP_FUNCTION(array_reduce) zval *input; zval args[2]; zval *operand; - zval retval; zend_fcall_info fci; - zend_fcall_info_cache fci_cache = empty_fcall_info_cache; + zend_fcall_info_cache fci_cache; zval *initial = NULL; HashTable *htbl; @@ -6469,8 +6450,7 @@ PHP_FUNCTION(array_reduce) Z_PARAM_ZVAL(initial) ZEND_PARSE_PARAMETERS_END(); - - if (ZEND_NUM_ARGS() > 2) { + if (initial) { ZVAL_COPY(return_value, initial); } else { ZVAL_NULL(return_value); @@ -6485,30 +6465,44 @@ PHP_FUNCTION(array_reduce) return; } - fci.retval = &retval; + fci.retval = return_value; fci.param_count = 2; + fci.params = args; ZEND_HASH_FOREACH_VAL(htbl, operand) { ZVAL_COPY_VALUE(&args[0], return_value); - ZVAL_COPY(&args[1], operand); - fci.params = args; + ZVAL_COPY_VALUE(&args[1], operand); - if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[0]); - ZVAL_COPY_VALUE(return_value, &retval); + zend_call_function(&fci, &fci_cache); + zval_ptr_dtor(&args[0]); + + if (EXPECTED(!Z_ISUNDEF_P(return_value))) { if (UNEXPECTED(Z_ISREF_P(return_value))) { zend_unwrap_reference(return_value); } } else { - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[0]); RETURN_NULL(); } } ZEND_HASH_FOREACH_END(); } /* }}} */ +/* Consumes `zv` */ +static bool php_is_true(zval *zv) +{ + switch (Z_TYPE_P(zv)) { + case IS_TRUE: + return true; + case IS_FALSE: + return false; + default: { + bool rv = zend_is_true(zv); + zval_ptr_dtor(zv); + return rv; + } + } +} + /* {{{ Filters elements from the array via the callback. */ PHP_FUNCTION(array_filter) { @@ -6521,7 +6515,7 @@ PHP_FUNCTION(array_filter) zend_long use_type = 0; zend_string *string_key; zend_fcall_info fci = empty_fcall_info; - zend_fcall_info_cache fci_cache = empty_fcall_info_cache; + zend_fcall_info_cache fci_cache; zend_ulong num_key; ZEND_PARSE_PARAMETERS_START(1, 3) @@ -6571,9 +6565,7 @@ PHP_FUNCTION(array_filter) RETURN_THROWS(); } - bool retval_true = zend_is_true(&retval); - zval_ptr_dtor(&retval); - if (!retval_true) { + if (!php_is_true(&retval)) { continue; } } else if (!zend_is_true(operand)) { @@ -6597,7 +6589,7 @@ enum php_array_find_result { PHP_ARRAY_FIND_SOME = 1, }; -static enum php_array_find_result php_array_find(const HashTable *array, zend_fcall_info fci, zend_fcall_info_cache fci_cache, zval *result_key, zval *result_value, bool negate_condition) +static enum php_array_find_result php_array_find(const HashTable *array, zend_fcall_info fci, zend_fcall_info_cache *fci_cache, zval *result_key, zval *result_value, bool negate_condition) { zend_ulong num_key; zend_string *str_key; @@ -6620,25 +6612,22 @@ static enum php_array_find_result php_array_find(const HashTable *array, zend_fc if (!str_key) { ZVAL_LONG(&args[1], num_key); } else { + /* Allows copying the numeric branch, without this branch, into the iteration code + * that checks for the packed array flag. */ + ZEND_ASSUME(!HT_IS_PACKED(array)); ZVAL_STR(&args[1], str_key); } ZVAL_COPY_VALUE(&args[0], operand); - zend_result result = zend_call_function(&fci, &fci_cache); + zend_result result = zend_call_function(&fci, fci_cache); ZEND_ASSERT(result == SUCCESS); if (UNEXPECTED(Z_ISUNDEF(retval))) { return PHP_ARRAY_FIND_EXCEPTION; } - bool retval_true = zend_is_true(&retval); - zval_ptr_dtor(&retval); - - /* This negates the condition, if negate_condition is true. Otherwise it does nothing with `retval_true`. */ - retval_true ^= negate_condition; - - if (retval_true) { + if (php_is_true(&retval) ^ negate_condition) { if (result_value != NULL) { ZVAL_COPY_DEREF(result_value, &args[0]); } @@ -6660,14 +6649,14 @@ PHP_FUNCTION(array_find) { HashTable *array; zend_fcall_info fci; - zend_fcall_info_cache fci_cache = empty_fcall_info_cache; + zend_fcall_info_cache fci_cache; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_ARRAY_HT(array) Z_PARAM_FUNC(fci, fci_cache) ZEND_PARSE_PARAMETERS_END(); - php_array_find(array, fci, fci_cache, NULL, return_value, false); + php_array_find(array, fci, &fci_cache, NULL, return_value, false); } /* }}} */ @@ -6676,14 +6665,14 @@ PHP_FUNCTION(array_find_key) { HashTable *array; zend_fcall_info fci; - zend_fcall_info_cache fci_cache = empty_fcall_info_cache; + zend_fcall_info_cache fci_cache; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_ARRAY_HT(array) Z_PARAM_FUNC(fci, fci_cache) ZEND_PARSE_PARAMETERS_END(); - php_array_find(array, fci, fci_cache, return_value, NULL, false); + php_array_find(array, fci, &fci_cache, return_value, NULL, false); } /* }}} */ @@ -6692,14 +6681,14 @@ PHP_FUNCTION(array_any) { HashTable *array; zend_fcall_info fci; - zend_fcall_info_cache fci_cache = empty_fcall_info_cache; + zend_fcall_info_cache fci_cache; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_ARRAY_HT(array) Z_PARAM_FUNC(fci, fci_cache) ZEND_PARSE_PARAMETERS_END(); - RETURN_BOOL(php_array_find(array, fci, fci_cache, NULL, NULL, false) == PHP_ARRAY_FIND_SOME); + RETURN_BOOL(php_array_find(array, fci, &fci_cache, NULL, NULL, false) == PHP_ARRAY_FIND_SOME); } /* }}} */ @@ -6708,14 +6697,14 @@ PHP_FUNCTION(array_all) { HashTable *array; zend_fcall_info fci; - zend_fcall_info_cache fci_cache = empty_fcall_info_cache; + zend_fcall_info_cache fci_cache; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_ARRAY_HT(array) Z_PARAM_FUNC(fci, fci_cache) ZEND_PARSE_PARAMETERS_END(); - RETURN_BOOL(php_array_find(array, fci, fci_cache, NULL, NULL, true) == PHP_ARRAY_FIND_NONE); + RETURN_BOOL(php_array_find(array, fci, &fci_cache, NULL, NULL, true) == PHP_ARRAY_FIND_NONE); } /* }}} */ @@ -6725,8 +6714,8 @@ PHP_FUNCTION(array_map) zval *arrays = NULL; int n_arrays = 0; zval result; - zend_fcall_info fci = empty_fcall_info; - zend_fcall_info_cache fci_cache = empty_fcall_info_cache; + zend_fcall_info fci; + zend_fcall_info_cache fci_cache; int i; uint32_t k, maxlen = 0; @@ -6736,16 +6725,12 @@ PHP_FUNCTION(array_map) ZEND_PARSE_PARAMETERS_END(); if (n_arrays == 1) { - zend_ulong num_key; - zend_string *str_key; - zval *zv, arg; - int ret; - if (Z_TYPE(arrays[0]) != IS_ARRAY) { zend_argument_type_error(2, "must be of type array, %s given", zend_zval_value_name(&arrays[0])); RETURN_THROWS(); } - maxlen = zend_hash_num_elements(Z_ARRVAL(arrays[0])); + const HashTable *input = Z_ARRVAL(arrays[0]); + maxlen = zend_hash_num_elements(input); /* Short-circuit: if no callback and only one array, just return it. */ if (!ZEND_FCI_INITIALIZED(fci) || !maxlen) { @@ -6753,27 +6738,60 @@ PHP_FUNCTION(array_map) return; } - array_init_size(return_value, maxlen); - zend_hash_real_init(Z_ARRVAL_P(return_value), HT_IS_PACKED(Z_ARRVAL(arrays[0]))); - - ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(arrays[0]), num_key, str_key, zv) { - fci.retval = &result; - fci.param_count = 1; - fci.params = &arg; - - ZVAL_COPY(&arg, zv); - ret = zend_call_function(&fci, &fci_cache); - i_zval_ptr_dtor(&arg); - if (ret != SUCCESS || Z_TYPE(result) == IS_UNDEF) { - zend_array_destroy(Z_ARR_P(return_value)); - RETURN_NULL(); - } - if (str_key) { - _zend_hash_append(Z_ARRVAL_P(return_value), str_key, &result); - } else { - zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, &result); - } - } ZEND_HASH_FOREACH_END(); + fci.retval = &result; + fci.param_count = 1; + + if (HT_IS_PACKED(input)) { + array_init_size(return_value, input->nNumUsed); + HashTable *output = Z_ARRVAL_P(return_value); + zend_hash_real_init_packed(output); + + uint32_t undefs = 0; + ZEND_HASH_FILL_PACKED(output) { + /* Can't use ZEND_HASH_PACKED_FOREACH_VAL() because we need to also account for the UNDEF values + * so the keys in the output array will match those of the input array. */ + for (zval *cur = input->arPacked, *end = input->arPacked + input->nNumUsed; cur != end; cur++) { + if (EXPECTED(!Z_ISUNDEF_P(cur))) { + fci.params = cur; + zend_result ret = zend_call_function(&fci, &fci_cache); + ZEND_ASSERT(ret == SUCCESS); + ZEND_IGNORE_VALUE(ret); + if (UNEXPECTED(Z_ISUNDEF(result))) { + ZEND_HASH_FILL_FINISH(); + zend_array_destroy(output); + RETURN_NULL(); + } + } else { + ZVAL_UNDEF(&result); + undefs++; + } + ZEND_HASH_FILL_ADD(&result); + } + } ZEND_HASH_FILL_END(); + output->nNumOfElements -= undefs; + } else { + zend_ulong num_key; + zend_string *str_key; + + array_init_size(return_value, maxlen); + HashTable *output = Z_ARRVAL_P(return_value); + zend_hash_real_init_mixed(output); + + ZEND_HASH_MAP_FOREACH_KEY_VAL(input, num_key, str_key, fci.params) { + zend_result ret = zend_call_function(&fci, &fci_cache); + ZEND_ASSERT(ret == SUCCESS); + ZEND_IGNORE_VALUE(ret); + if (UNEXPECTED(Z_ISUNDEF(result))) { + zend_array_destroy(output); + RETURN_NULL(); + } + if (str_key) { + _zend_hash_append(output, str_key, &result); + } else { + zend_hash_index_add_new(output, num_key, &result); + } + } ZEND_HASH_FOREACH_END(); + } } else { uint32_t *array_pos = (HashPosition *)ecalloc(n_arrays, sizeof(HashPosition)); @@ -6874,7 +6892,11 @@ PHP_FUNCTION(array_map) fci.param_count = n_arrays; fci.params = params; - if (zend_call_function(&fci, &fci_cache) != SUCCESS || Z_TYPE(result) == IS_UNDEF) { + zend_result ret = zend_call_function(&fci, &fci_cache); + ZEND_ASSERT(ret == SUCCESS); + ZEND_IGNORE_VALUE(ret); + + if (Z_TYPE(result) == IS_UNDEF) { efree(array_pos); zend_array_destroy(Z_ARR_P(return_value)); for (i = 0; i < n_arrays; i++) { diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 1aae3fcd2c255..19e3e29bedff3 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -216,31 +216,16 @@ static void php_putenv_destructor(zval *zv) /* {{{ */ static void basic_globals_ctor(php_basic_globals *basic_globals_p) /* {{{ */ { - BG(umask) = -1; - BG(user_tick_functions) = NULL; - BG(user_filter_map) = NULL; - BG(serialize_lock) = 0; - - memset(&BG(serialize), 0, sizeof(BG(serialize))); - memset(&BG(unserialize), 0, sizeof(BG(unserialize))); - - memset(&BG(url_adapt_session_ex), 0, sizeof(BG(url_adapt_session_ex))); - memset(&BG(url_adapt_output_ex), 0, sizeof(BG(url_adapt_output_ex))); + memset(basic_globals_p, 0, sizeof(php_basic_globals)); - BG(url_adapt_session_ex).type = 1; - BG(url_adapt_output_ex).type = 0; + basic_globals_p->umask = -1; + basic_globals_p->url_adapt_session_ex.type = 1; - zend_hash_init(&BG(url_adapt_session_hosts_ht), 0, NULL, NULL, 1); - zend_hash_init(&BG(url_adapt_output_hosts_ht), 0, NULL, NULL, 1); - -#if defined(_REENTRANT) - memset(&BG(mblen_state), 0, sizeof(BG(mblen_state))); -#endif - - BG(page_uid) = -1; - BG(page_gid) = -1; + zend_hash_init(&basic_globals_p->url_adapt_session_hosts_ht, 0, NULL, NULL, 1); + zend_hash_init(&basic_globals_p->url_adapt_output_hosts_ht, 0, NULL, NULL, 1); - BG(syslog_device) = NULL; + basic_globals_p->page_uid = -1; + basic_globals_p->page_gid = -1; } /* }}} */ diff --git a/ext/standard/dir.c b/ext/standard/dir.c index a2a50eab7f51d..b468681ac364a 100644 --- a/ext/standard/dir.c +++ b/ext/standard/dir.c @@ -59,39 +59,6 @@ static zend_function *dir_class_get_constructor(zend_object *object) return NULL; } -#define FETCH_DIRP() \ - myself = getThis(); \ - if (!myself) { \ - ZEND_PARSE_PARAMETERS_START(0, 1) \ - Z_PARAM_OPTIONAL \ - Z_PARAM_RESOURCE_OR_NULL(id) \ - ZEND_PARSE_PARAMETERS_END(); \ - if (id) { \ - if ((dirp = (php_stream *)zend_fetch_resource(Z_RES_P(id), "Directory", php_file_le_stream())) == NULL) { \ - RETURN_THROWS(); \ - } \ - } else { \ - if (!DIRG(default_dir)) { \ - zend_type_error("No resource supplied"); \ - RETURN_THROWS(); \ - } \ - if ((dirp = (php_stream *)zend_fetch_resource(DIRG(default_dir), "Directory", php_file_le_stream())) == NULL) { \ - RETURN_THROWS(); \ - } \ - } \ - } else { \ - ZEND_PARSE_PARAMETERS_NONE(); \ - zval *handle_zv = Z_DIRECTORY_HANDLE_P(myself); \ - if (Z_TYPE_P(handle_zv) != IS_RESOURCE) { \ - zend_throw_error(NULL, "Unable to find my handle property"); \ - RETURN_THROWS(); \ - } \ - if ((dirp = (php_stream *)zend_fetch_resource_ex(handle_zv, "Directory", php_file_le_stream())) == NULL) { \ - RETURN_THROWS(); \ - } \ - } - - static void php_set_default_dir(zend_resource *res) { if (DIRG(default_dir)) { @@ -189,29 +156,159 @@ PHP_FUNCTION(dir) } /* }}} */ + +static php_stream* php_dir_get_directory_stream_from_user_arg(php_stream *dir_stream) +{ + if (dir_stream == NULL) { + if (UNEXPECTED(DIRG(default_dir) == NULL)) { + zend_type_error("No resource supplied"); + return NULL; + } + zend_resource *res = DIRG(default_dir); + ZEND_ASSERT(res->type == php_file_le_stream()); + dir_stream = (php_stream*) res->ptr; + } + + if (UNEXPECTED((dir_stream->flags & PHP_STREAM_FLAG_IS_DIR)) == 0) { + zend_argument_type_error(1, "must be a valid Directory resource"); + return NULL; + } + return dir_stream; +} + +static php_stream* php_dir_get_directory_stream_from_this(zval *this_z) +{ + zval *handle_zv = Z_DIRECTORY_HANDLE_P(this_z); + if (UNEXPECTED(Z_TYPE_P(handle_zv) != IS_RESOURCE)) { + zend_throw_error(NULL, "Internal directory stream has been altered"); + return NULL; + } + zend_resource *res = Z_RES_P(handle_zv); + /* Assume the close() method was called + * (instead of the hacky case where a different resource would have been set via the ArrayObject "hack") */ + if (UNEXPECTED(res->type != php_file_le_stream())) { + /* TypeError is used for BC, TODO: Use base Error in PHP 9 */ + zend_type_error("Directory::%s(): cannot use Directory resource after it has been closed", get_active_function_name()); + return NULL; + } + php_stream *dir_stream = (php_stream*) res->ptr; + if (UNEXPECTED((dir_stream->flags & PHP_STREAM_FLAG_IS_DIR)) == 0) { + zend_throw_error(NULL, "Internal directory stream has been altered"); + return NULL; + } + return dir_stream; +} + /* {{{ Close directory connection identified by the dir_handle */ PHP_FUNCTION(closedir) { - zval *id = NULL, *myself; - php_stream *dirp; - zend_resource *res; + php_stream *dirp = NULL; - FETCH_DIRP(); + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + PHP_Z_PARAM_STREAM_OR_NULL(dirp) + ZEND_PARSE_PARAMETERS_END(); - if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) { - zend_argument_type_error(1, "must be a valid Directory resource"); + dirp = php_dir_get_directory_stream_from_user_arg(dirp); + if (UNEXPECTED(dirp == NULL)) { + RETURN_THROWS(); + } + zend_resource *res = dirp->res; + zend_list_close(res); + + if (res == DIRG(default_dir)) { + php_set_default_dir(NULL); + } +} +/* }}} */ + +PHP_METHOD(Directory, close) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_stream *dirp = php_dir_get_directory_stream_from_this(ZEND_THIS); + if (UNEXPECTED(dirp == NULL)) { RETURN_THROWS(); } - res = dirp->res; - zend_list_close(dirp->res); + zend_resource *res = dirp->res; + zend_list_close(res); if (res == DIRG(default_dir)) { php_set_default_dir(NULL); } } + +/* {{{ Rewind dir_handle back to the start */ +PHP_FUNCTION(rewinddir) +{ + php_stream *dirp = NULL; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + PHP_Z_PARAM_STREAM_OR_NULL(dirp) + ZEND_PARSE_PARAMETERS_END(); + + dirp = php_dir_get_directory_stream_from_user_arg(dirp); + if (UNEXPECTED(dirp == NULL)) { + RETURN_THROWS(); + } + + php_stream_rewinddir(dirp); +} +/* }}} */ + +PHP_METHOD(Directory, rewind) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_stream *dirp = php_dir_get_directory_stream_from_this(ZEND_THIS); + if (UNEXPECTED(dirp == NULL)) { + RETURN_THROWS(); + } + + php_stream_rewinddir(dirp); +} + +/* {{{ Read directory entry from dir_handle */ +PHP_FUNCTION(readdir) +{ + php_stream *dirp = NULL; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + PHP_Z_PARAM_STREAM_OR_NULL(dirp) + ZEND_PARSE_PARAMETERS_END(); + + dirp = php_dir_get_directory_stream_from_user_arg(dirp); + if (UNEXPECTED(dirp == NULL)) { + RETURN_THROWS(); + } + + php_stream_dirent entry; + if (php_stream_readdir(dirp, &entry)) { + RETURN_STRING(entry.d_name); + } + RETURN_FALSE; +} /* }}} */ +PHP_METHOD(Directory, read) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_stream *dirp = php_dir_get_directory_stream_from_this(ZEND_THIS); + if (UNEXPECTED(dirp == NULL)) { + RETURN_THROWS(); + } + + php_stream_dirent entry; + if (php_stream_readdir(dirp, &entry)) { + RETURN_STRING(entry.d_name); + } + RETURN_FALSE; +} + #if defined(HAVE_CHROOT) && !defined(ZTS) && defined(ENABLE_CHROOT_FUNC) /* {{{ Change root directory */ PHP_FUNCTION(chroot) @@ -300,44 +397,6 @@ PHP_FUNCTION(getcwd) } /* }}} */ -/* {{{ Rewind dir_handle back to the start */ -PHP_FUNCTION(rewinddir) -{ - zval *id = NULL, *myself; - php_stream *dirp; - - FETCH_DIRP(); - - if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) { - zend_argument_type_error(1, "must be a valid Directory resource"); - RETURN_THROWS(); - } - - php_stream_rewinddir(dirp); -} -/* }}} */ - -/* {{{ Read directory entry from dir_handle */ -PHP_FUNCTION(readdir) -{ - zval *id = NULL, *myself; - php_stream *dirp; - php_stream_dirent entry; - - FETCH_DIRP(); - - if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) { - zend_argument_type_error(1, "must be a valid Directory resource"); - RETURN_THROWS(); - } - - if (php_stream_readdir(dirp, &entry)) { - RETURN_STRINGL(entry.d_name, strlen(entry.d_name)); - } - RETURN_FALSE; -} -/* }}} */ - #ifdef HAVE_GLOB /* {{{ Find pathnames matching a pattern */ PHP_FUNCTION(glob) diff --git a/ext/standard/dir.stub.php b/ext/standard/dir.stub.php index 457a965352516..afca1fcacc421 100644 --- a/ext/standard/dir.stub.php +++ b/ext/standard/dir.stub.php @@ -98,18 +98,9 @@ final class Directory /** @var resource */ public readonly mixed $handle; - /** - * @implementation-alias closedir - */ public function close(): void {} - /** - * @implementation-alias rewinddir - */ public function rewind(): void {} - /** - * @implementation-alias readdir - */ public function read(): string|false {} } diff --git a/ext/standard/dir_arginfo.h b/ext/standard/dir_arginfo.h index 9b293f3cd753f..f73b0e5d86ad1 100644 --- a/ext/standard/dir_arginfo.h +++ b/ext/standard/dir_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 069117bab1b9502faf516307aa7e80308f7b7f13 */ + * Stub hash: 543d0d12062ed88dab7a3ac4354499682c5c7166 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Directory_close, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() @@ -9,14 +9,14 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Directory_read, 0, 0, MAY_BE_STRING|MAY_BE_FALSE) ZEND_END_ARG_INFO() -ZEND_FUNCTION(closedir); -ZEND_FUNCTION(rewinddir); -ZEND_FUNCTION(readdir); +ZEND_METHOD(Directory, close); +ZEND_METHOD(Directory, rewind); +ZEND_METHOD(Directory, read); static const zend_function_entry class_Directory_methods[] = { - ZEND_RAW_FENTRY("close", zif_closedir, arginfo_class_Directory_close, ZEND_ACC_PUBLIC, NULL, NULL) - ZEND_RAW_FENTRY("rewind", zif_rewinddir, arginfo_class_Directory_rewind, ZEND_ACC_PUBLIC, NULL, NULL) - ZEND_RAW_FENTRY("read", zif_readdir, arginfo_class_Directory_read, ZEND_ACC_PUBLIC, NULL, NULL) + ZEND_ME(Directory, close, arginfo_class_Directory_close, ZEND_ACC_PUBLIC) + ZEND_ME(Directory, rewind, arginfo_class_Directory_rewind, ZEND_ACC_PUBLIC) + ZEND_ME(Directory, read, arginfo_class_Directory_read, ZEND_ACC_PUBLIC) ZEND_FE_END }; diff --git a/ext/standard/exec.c b/ext/standard/exec.c index 1df46cc050b01..ce3e8565ad200 100644 --- a/ext/standard/exec.c +++ b/ext/standard/exec.c @@ -118,7 +118,7 @@ PHPAPI int php_exec(int type, const char *cmd, zval *array, zval *return_value) php_stream *stream; size_t buflen, bufl = 0; #if PHP_SIGCHILD - void (*sig_handler)() = signal(SIGCHLD, SIG_DFL); + void (*sig_handler)(int) = signal(SIGCHLD, SIG_DFL); #endif #ifdef PHP_WIN32 diff --git a/ext/standard/file.c b/ext/standard/file.c index 908aee85a2e74..4e136bedf5fab 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -757,7 +757,7 @@ PHPAPI PHP_FUNCTION(fclose) ZEND_PARSE_PARAMETERS_END(); if ((stream->flags & PHP_STREAM_FLAG_NO_FCLOSE) != 0) { - php_error_docref(NULL, E_WARNING, ZEND_LONG_FMT " is not a valid stream resource", stream->res->handle); + php_error_docref(NULL, E_WARNING, "cannot close the provided stream, as it must not be manually closed"); RETURN_FALSE; } diff --git a/ext/standard/file.h b/ext/standard/file.h index 3a9cf1435b143..f8faebd028293 100644 --- a/ext/standard/file.h +++ b/ext/standard/file.h @@ -36,7 +36,6 @@ PHPAPI PHP_FUNCTION(fpassthru); PHP_MINIT_FUNCTION(user_streams); -PHPAPI int php_le_stream_context(void); PHPAPI zend_result php_copy_file(const char *src, const char *dest); PHPAPI zend_result php_copy_file_ex(const char *src, const char *dest, int src_flags); PHPAPI zend_result php_copy_file_ctx(const char *src, const char *dest, int src_flags, php_stream_context *ctx); diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index fff6af5e2143c..ea06e9dff61ea 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -67,15 +67,16 @@ #include "php_fopen_wrappers.h" -#define HTTP_HEADER_BLOCK_SIZE 1024 -#define PHP_URL_REDIRECT_MAX 20 -#define HTTP_HEADER_USER_AGENT 1 -#define HTTP_HEADER_HOST 2 -#define HTTP_HEADER_AUTH 4 -#define HTTP_HEADER_FROM 8 -#define HTTP_HEADER_CONTENT_LENGTH 16 -#define HTTP_HEADER_TYPE 32 -#define HTTP_HEADER_CONNECTION 64 +#define HTTP_HEADER_BLOCK_SIZE 1024 +#define HTTP_HEADER_MAX_LOCATION_SIZE 8182 /* 8192 - 10 (size of "Location: ") */ +#define PHP_URL_REDIRECT_MAX 20 +#define HTTP_HEADER_USER_AGENT 1 +#define HTTP_HEADER_HOST 2 +#define HTTP_HEADER_AUTH 4 +#define HTTP_HEADER_FROM 8 +#define HTTP_HEADER_CONTENT_LENGTH 16 +#define HTTP_HEADER_TYPE 32 +#define HTTP_HEADER_CONNECTION 64 #define HTTP_WRAPPER_HEADER_INIT 1 #define HTTP_WRAPPER_REDIRECTED 2 @@ -107,7 +108,7 @@ static inline void strip_header(char *header_bag, char *lc_header_bag, static bool check_has_header(const char *headers, const char *header) { const char *s = headers; while ((s = strstr(s, header))) { - if (s == headers || *(s-1) == '\n') { + if (s == headers || (*(s-1) == '\n' && *(s-2) == '\r')) { return 1; } s++; @@ -143,6 +144,214 @@ static zend_result php_stream_handle_proxy_authorization_header(const char *s, s return FAILURE; } +typedef struct _php_stream_http_response_header_info { + php_stream_filter *transfer_encoding; + size_t file_size; + bool error; + bool follow_location; + char *location; + size_t location_len; +} php_stream_http_response_header_info; + +static void php_stream_http_response_header_info_init( + php_stream_http_response_header_info *header_info) +{ + memset(header_info, 0, sizeof(php_stream_http_response_header_info)); + header_info->follow_location = 1; +} + +/* Trim white spaces from response header line and update its length */ +static bool php_stream_http_response_header_trim(char *http_header_line, + size_t *http_header_line_length) +{ + char *http_header_line_end = http_header_line + *http_header_line_length - 1; + while (http_header_line_end >= http_header_line && + (*http_header_line_end == '\n' || *http_header_line_end == '\r')) { + http_header_line_end--; + } + + /* The primary definition of an HTTP header in RFC 7230 states: + * > Each header field consists of a case-insensitive field name followed + * > by a colon (":"), optional leading whitespace, the field value, and + * > optional trailing whitespace. */ + + /* Strip trailing whitespace */ + bool space_trim = (*http_header_line_end == ' ' || *http_header_line_end == '\t'); + if (space_trim) { + do { + http_header_line_end--; + } while (http_header_line_end >= http_header_line && + (*http_header_line_end == ' ' || *http_header_line_end == '\t')); + } + http_header_line_end++; + *http_header_line_end = '\0'; + *http_header_line_length = http_header_line_end - http_header_line; + + return space_trim; +} + +/* Process folding headers of the current line and if there are none, parse last full response + * header line. It returns NULL if the last header is finished, otherwise it returns updated + * last header line. */ +static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *wrapper, + php_stream *stream, php_stream_context *context, int options, + zend_string *last_header_line_str, char *header_line, size_t *header_line_length, + int response_code, zval *response_header, + php_stream_http_response_header_info *header_info) +{ + char *last_header_line = ZSTR_VAL(last_header_line_str); + size_t last_header_line_length = ZSTR_LEN(last_header_line_str); + char *last_header_line_end = ZSTR_VAL(last_header_line_str) + ZSTR_LEN(last_header_line_str) - 1; + + /* Process non empty header line. */ + if (header_line && (*header_line != '\n' && *header_line != '\r')) { + /* Removing trailing white spaces. */ + if (php_stream_http_response_header_trim(header_line, header_line_length) && + *header_line_length == 0) { + /* Only spaces so treat as an empty folding header. */ + return last_header_line_str; + } + + /* Process folding headers if starting with a space or a tab. */ + if (header_line && (*header_line == ' ' || *header_line == '\t')) { + char *http_folded_header_line = header_line; + size_t http_folded_header_line_length = *header_line_length; + /* Remove the leading white spaces. */ + while (*http_folded_header_line == ' ' || *http_folded_header_line == '\t') { + http_folded_header_line++; + http_folded_header_line_length--; + } + /* It has to have some characters because it would get returned after the call + * php_stream_http_response_header_trim above. */ + ZEND_ASSERT(http_folded_header_line_length > 0); + /* Concatenate last header line, space and current header line. */ + zend_string *extended_header_str = zend_string_concat3( + last_header_line, last_header_line_length, + " ", 1, + http_folded_header_line, http_folded_header_line_length); + zend_string_efree(last_header_line_str); + last_header_line_str = extended_header_str; + /* Return new header line. */ + return last_header_line_str; + } + } + + /* Find header separator position. */ + char *last_header_value = memchr(last_header_line, ':', last_header_line_length); + if (last_header_value) { + /* Verify there is no space in header name */ + char *last_header_name = last_header_line + 1; + while (last_header_name < last_header_value) { + if (*last_header_name == ' ' || *last_header_name == '\t') { + header_info->error = true; + php_stream_wrapper_log_error(wrapper, options, + "HTTP invalid response format (space in header name)!"); + zend_string_efree(last_header_line_str); + return NULL; + } + ++last_header_name; + } + + last_header_value++; /* Skip ':'. */ + + /* Strip leading whitespace. */ + while (last_header_value < last_header_line_end + && (*last_header_value == ' ' || *last_header_value == '\t')) { + last_header_value++; + } + } else { + /* There is no colon which means invalid response so error. */ + header_info->error = true; + php_stream_wrapper_log_error(wrapper, options, + "HTTP invalid response format (no colon in header line)!"); + zend_string_efree(last_header_line_str); + return NULL; + } + + bool store_header = true; + zval *tmpzval = NULL; + + if (!strncasecmp(last_header_line, "Location:", sizeof("Location:")-1)) { + /* Check if the location should be followed. */ + if (context && (tmpzval = php_stream_context_get_option(context, "http", "follow_location")) != NULL) { + header_info->follow_location = zval_is_true(tmpzval); + } else if (!((response_code >= 300 && response_code < 304) + || 307 == response_code || 308 == response_code)) { + /* The redirection should not be automatic if follow_location is not set and + * response_code not in (300, 301, 302, 303 and 307) + * see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1 + * RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */ + header_info->follow_location = 0; + } + size_t last_header_value_len = strlen(last_header_value); + if (last_header_value_len > HTTP_HEADER_MAX_LOCATION_SIZE) { + header_info->error = true; + php_stream_wrapper_log_error(wrapper, options, + "HTTP Location header size is over the limit of %d bytes", + HTTP_HEADER_MAX_LOCATION_SIZE); + zend_string_efree(last_header_line_str); + return NULL; + } + if (header_info->location_len == 0) { + header_info->location = emalloc(last_header_value_len + 1); + } else if (header_info->location_len <= last_header_value_len) { + header_info->location = erealloc(header_info->location, last_header_value_len + 1); + } + header_info->location_len = last_header_value_len; + memcpy(header_info->location, last_header_value, last_header_value_len + 1); + } else if (!strncasecmp(last_header_line, "Content-Type:", sizeof("Content-Type:")-1)) { + php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, last_header_value, 0); + } else if (!strncasecmp(last_header_line, "Content-Length:", sizeof("Content-Length:")-1)) { + /* https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length */ + const char *ptr = last_header_value; + /* must contain only digits, no + or - symbols */ + if (*ptr >= '0' && *ptr <= '9') { + char *endptr = NULL; + size_t parsed = ZEND_STRTOUL(ptr, &endptr, 10); + /* check whether there was no garbage in the header value and the conversion was successful */ + if (endptr && !*endptr) { + /* truncate for 32-bit such that no negative file sizes occur */ + header_info->file_size = MIN(parsed, ZEND_LONG_MAX); + php_stream_notify_file_size(context, header_info->file_size, last_header_line, 0); + } + } + } else if ( + !strncasecmp(last_header_line, "Transfer-Encoding:", sizeof("Transfer-Encoding:")-1) + && !strncasecmp(last_header_value, "Chunked", sizeof("Chunked")-1) + ) { + /* Create filter to decode response body. */ + if (!(options & STREAM_ONLY_GET_HEADERS)) { + bool decode = true; + + if (context && (tmpzval = php_stream_context_get_option(context, "http", "auto_decode")) != NULL) { + decode = zend_is_true(tmpzval); + } + if (decode) { + if (header_info->transfer_encoding != NULL) { + /* Prevent a memory leak in case there are more transfer-encoding headers. */ + php_stream_filter_free(header_info->transfer_encoding); + } + header_info->transfer_encoding = php_stream_filter_create( + "dechunk", NULL, php_stream_is_persistent(stream)); + if (header_info->transfer_encoding != NULL) { + /* Do not store transfer-encoding header. */ + store_header = false; + } + } + } + } + + if (store_header) { + zval http_header; + ZVAL_NEW_STR(&http_header, last_header_line_str); + zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header); + } else { + zend_string_efree(last_header_line_str); + } + + return NULL; +} + static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, zend_string **opened_path, php_stream_context *context, int redirect_max, int flags, @@ -155,11 +364,12 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, zend_string *tmp = NULL; char *ua_str = NULL; zval *ua_zval = NULL, *tmpzval = NULL, ssl_proxy_peer_name; - char location[HTTP_HEADER_BLOCK_SIZE]; int reqok = 0; char *http_header_line = NULL; + zend_string *last_header_line_str = NULL; + php_stream_http_response_header_info header_info; char tmp_line[128]; - size_t chunk_size = 0, file_size = 0; + size_t chunk_size = 0; int eol_detect = 0; zend_string *transport_string; zend_string *errstr = NULL; @@ -170,8 +380,6 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, int header_init = ((flags & HTTP_WRAPPER_HEADER_INIT) != 0); int redirected = ((flags & HTTP_WRAPPER_REDIRECTED) != 0); int redirect_keep_method = ((flags & HTTP_WRAPPER_KEEP_METHOD) != 0); - bool follow_location = 1; - php_stream_filter *transfer_encoding = NULL; int response_code; smart_str req_buf = {0}; bool custom_request_method; @@ -360,6 +568,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } } + php_stream_http_response_header_info_init(&header_info); + if (stream == NULL) goto out; @@ -660,8 +870,6 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, /* send it */ php_stream_write(stream, ZSTR_VAL(req_buf.s), ZSTR_LEN(req_buf.s)); - location[0] = '\0'; - if (Z_ISUNDEF_P(response_header)) { array_init(response_header); } @@ -744,140 +952,103 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } /* read past HTTP headers */ - while (!php_stream_eof(stream)) { size_t http_header_line_length; if (http_header_line != NULL) { efree(http_header_line); } - if ((http_header_line = php_stream_get_line(stream, NULL, 0, &http_header_line_length)) && *http_header_line != '\n' && *http_header_line != '\r') { - char *e = http_header_line + http_header_line_length - 1; - char *http_header_value; - - while (e >= http_header_line && (*e == '\n' || *e == '\r')) { - e--; - } - - /* The primary definition of an HTTP header in RFC 7230 states: - * > Each header field consists of a case-insensitive field name followed - * > by a colon (":"), optional leading whitespace, the field value, and - * > optional trailing whitespace. */ - - /* Strip trailing whitespace */ - while (e >= http_header_line && (*e == ' ' || *e == '\t')) { - e--; - } - - /* Terminate header line */ - e++; - *e = '\0'; - http_header_line_length = e - http_header_line; - - http_header_value = memchr(http_header_line, ':', http_header_line_length); - if (http_header_value) { - http_header_value++; /* Skip ':' */ - - /* Strip leading whitespace */ - while (http_header_value < e - && (*http_header_value == ' ' || *http_header_value == '\t')) { - http_header_value++; + if ((http_header_line = php_stream_get_line(stream, NULL, 0, &http_header_line_length))) { + bool last_line; + if (*http_header_line == '\r') { + if (http_header_line[1] != '\n') { + php_stream_close(stream); + stream = NULL; + php_stream_wrapper_log_error(wrapper, options, + "HTTP invalid header name (cannot start with CR character)!"); + goto out; } + last_line = true; + } else if (*http_header_line == '\n') { + last_line = true; } else { - /* There is no colon. Set the value to the end of the header line, which is - * effectively an empty string. */ - http_header_value = e; + last_line = false; } - - if (!strncasecmp(http_header_line, "Location:", sizeof("Location:")-1)) { - if (context && (tmpzval = php_stream_context_get_option(context, "http", "follow_location")) != NULL) { - follow_location = zval_is_true(tmpzval); - } else if (!((response_code >= 300 && response_code < 304) - || 307 == response_code || 308 == response_code)) { - /* we shouldn't redirect automatically - if follow_location isn't set and response_code not in (300, 301, 302, 303 and 307) - see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1 - RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */ - follow_location = 0; - } - strlcpy(location, http_header_value, sizeof(location)); - } else if (!strncasecmp(http_header_line, "Content-Type:", sizeof("Content-Type:")-1)) { - php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_value, 0); - } else if (!strncasecmp(http_header_line, "Content-Length:", sizeof("Content-Length:")-1)) { - /* https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length */ - const char *ptr = http_header_value; - /* must contain only digits, no + or - symbols */ - if (*ptr >= '0' && *ptr <= '9') { - char *endptr = NULL; - size_t parsed = ZEND_STRTOUL(ptr, &endptr, 10); - /* check whether there was no garbage in the header value and the conversion was successful */ - if (endptr && !*endptr) { - /* truncate for 32-bit such that no negative file sizes occur */ - file_size = MIN(parsed, ZEND_LONG_MAX); - php_stream_notify_file_size(context, file_size, http_header_line, 0); + + if (last_header_line_str != NULL) { + /* Parse last header line. */ + last_header_line_str = php_stream_http_response_headers_parse(wrapper, stream, + context, options, last_header_line_str, http_header_line, + &http_header_line_length, response_code, response_header, &header_info); + if (EXPECTED(last_header_line_str == NULL)) { + if (UNEXPECTED(header_info.error)) { + php_stream_close(stream); + stream = NULL; + goto out; } + } else { + /* Folding header present so continue. */ + continue; } - } else if ( - !strncasecmp(http_header_line, "Transfer-Encoding:", sizeof("Transfer-Encoding:")-1) - && !strncasecmp(http_header_value, "Chunked", sizeof("Chunked")-1) - ) { - - /* create filter to decode response body */ - if (!(options & STREAM_ONLY_GET_HEADERS)) { - bool decode = true; - - if (context && (tmpzval = php_stream_context_get_option(context, "http", "auto_decode")) != NULL) { - decode = zend_is_true(tmpzval); - } - if (decode) { - transfer_encoding = php_stream_filter_create("dechunk", NULL, php_stream_is_persistent(stream)); - if (transfer_encoding) { - /* don't store transfer-encodeing header */ - continue; - } - } + } else if (!last_line) { + /* The first line cannot start with spaces. */ + if (*http_header_line == ' ' || *http_header_line == '\t') { + php_stream_close(stream); + stream = NULL; + php_stream_wrapper_log_error(wrapper, options, + "HTTP invalid response format (folding header at the start)!"); + goto out; } + /* Trim the first line if it is not the last line. */ + php_stream_http_response_header_trim(http_header_line, &http_header_line_length); } - - { - zval http_header; - ZVAL_STRINGL(&http_header, http_header_line, http_header_line_length); - zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header); + if (last_line) { + /* For the last line the last header line must be NULL. */ + ZEND_ASSERT(last_header_line_str == NULL); + break; } + /* Save current line as the last line so it gets parsed in the next round. */ + last_header_line_str = zend_string_init(http_header_line, http_header_line_length, 0); } else { break; } } - if (!reqok || (location[0] != '\0' && follow_location)) { - if (!follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) { + /* If the stream was closed early, we still want to process the last line to keep BC. */ + if (last_header_line_str != NULL) { + php_stream_http_response_headers_parse(wrapper, stream, context, options, + last_header_line_str, NULL, NULL, response_code, response_header, &header_info); + } + + if (!reqok || (header_info.location != NULL && header_info.follow_location)) { + if (!header_info.follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) { goto out; } - if (location[0] != '\0') - php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, location, 0); + if (header_info.location != NULL) + php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, header_info.location, 0); php_stream_close(stream); stream = NULL; - if (transfer_encoding) { - php_stream_filter_free(transfer_encoding); - transfer_encoding = NULL; + if (header_info.transfer_encoding) { + php_stream_filter_free(header_info.transfer_encoding); + header_info.transfer_encoding = NULL; } - if (location[0] != '\0') { + if (header_info.location != NULL) { - char new_path[HTTP_HEADER_BLOCK_SIZE]; - char loc_path[HTTP_HEADER_BLOCK_SIZE]; + char *new_path = NULL; - *new_path='\0'; - if (strlen(location)<8 || (strncasecmp(location, "https://", sizeof("https://")-1) && - strncasecmp(location, "https://", sizeof("https://")-1) && - strncasecmp(location, "ftp://", sizeof("ftp://")-1) && - strncasecmp(location, "ftps://", sizeof("ftps://")-1))) + if (strlen(header_info.location) < 8 || + (strncasecmp(header_info.location, "https://", sizeof("https://")-1) && + strncasecmp(header_info.location, "https://", sizeof("https://")-1) && + strncasecmp(header_info.location, "ftp://", sizeof("ftp://")-1) && + strncasecmp(header_info.location, "ftps://", sizeof("ftps://")-1))) { - if (*location != '/') { - if (*(location+1) != '\0' && resource->path) { + char *loc_path = NULL; + if (*header_info.location != '/') { + if (*(header_info.location+1) != '\0' && resource->path) { char *s = strrchr(ZSTR_VAL(resource->path), '/'); if (!s) { s = ZSTR_VAL(resource->path); @@ -893,29 +1064,35 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (resource->path && ZSTR_VAL(resource->path)[0] == '/' && ZSTR_VAL(resource->path)[1] == '\0') { - snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", ZSTR_VAL(resource->path), location); + spprintf(&loc_path, 0, "%s%s", ZSTR_VAL(resource->path), header_info.location); } else { - snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", ZSTR_VAL(resource->path), location); + spprintf(&loc_path, 0, "%s/%s", ZSTR_VAL(resource->path), header_info.location); } } else { - snprintf(loc_path, sizeof(loc_path) - 1, "/%s", location); + spprintf(&loc_path, 0, "/%s", header_info.location); } } else { - strlcpy(loc_path, location, sizeof(loc_path)); + loc_path = header_info.location; + header_info.location = NULL; } if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) { - snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), resource->port, loc_path); + spprintf(&new_path, 0, "%s://%s:%d%s", ZSTR_VAL(resource->scheme), + ZSTR_VAL(resource->host), resource->port, loc_path); } else { - snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), loc_path); + spprintf(&new_path, 0, "%s://%s%s", ZSTR_VAL(resource->scheme), + ZSTR_VAL(resource->host), loc_path); } + efree(loc_path); } else { - strlcpy(new_path, location, sizeof(new_path)); + new_path = header_info.location; + header_info.location = NULL; } php_url_free(resource); /* check for invalid redirection URLs */ if ((resource = php_url_parse(new_path)) == NULL) { php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); + efree(new_path); goto out; } @@ -927,6 +1104,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, while (s < e) { \ if (iscntrl(*s)) { \ php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); \ + efree(new_path); \ goto out; \ } \ s++; \ @@ -949,6 +1127,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, stream = php_stream_url_wrap_http_ex( wrapper, new_path, mode, options, opened_path, context, --redirect_max, new_flags, response_header STREAMS_CC); + efree(new_path); } else { php_stream_wrapper_log_error(wrapper, options, "HTTP request failed! %s", tmp_line); } @@ -961,6 +1140,10 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, efree(http_header_line); } + if (header_info.location != NULL) { + efree(header_info.location); + } + if (resource) { php_url_free(resource); } @@ -969,7 +1152,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (header_init) { ZVAL_COPY(&stream->wrapperdata, response_header); } - php_stream_notify_progress_init(context, 0, file_size); + php_stream_notify_progress_init(context, 0, header_info.file_size); /* Restore original chunk size now that we're done with headers */ if (options & STREAM_WILL_CAST) @@ -985,8 +1168,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, /* restore mode */ strlcpy(stream->mode, mode, sizeof(stream->mode)); - if (transfer_encoding) { - php_stream_filter_append(&stream->readfilters, transfer_encoding); + if (header_info.transfer_encoding) { + php_stream_filter_append(&stream->readfilters, header_info.transfer_encoding); } /* It's possible that the server already sent in more data than just the headers. diff --git a/ext/standard/info.c b/ext/standard/info.c index 0211265f954a9..952f0f92fe6e2 100644 --- a/ext/standard/info.c +++ b/ext/standard/info.c @@ -805,9 +805,9 @@ PHPAPI ZEND_COLD void php_print_info(int flag) #ifdef PHP_BUILD_SYSTEM php_info_print_table_row(2, "Build System", PHP_BUILD_SYSTEM); #endif -#ifdef PHP_BUILD_PROVIDER - php_info_print_table_row(2, "Build Provider", PHP_BUILD_PROVIDER); -#endif + if (php_build_provider()) { + php_info_print_table_row(2, "Build Provider", php_build_provider()); + } #ifdef PHP_BUILD_COMPILER php_info_print_table_row(2, "Compiler", PHP_BUILD_COMPILER); #endif diff --git a/ext/standard/iptc.c b/ext/standard/iptc.c index e4dd38637570a..44dd33bab10ac 100644 --- a/ext/standard/iptc.c +++ b/ext/standard/iptc.c @@ -204,6 +204,7 @@ PHP_FUNCTION(iptcembed) if (spool < 2) { if (zend_fstat(fileno(fp), &sb) != 0) { + fclose(fp); RETURN_FALSE; } diff --git a/ext/standard/mail.c b/ext/standard/mail.c index 35c23a0be76c0..0243ec897a05e 100644 --- a/ext/standard/mail.c +++ b/ext/standard/mail.c @@ -445,7 +445,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c const char *hdr = headers; char *ahdr = NULL; #if PHP_SIGCHILD - void (*sig_handler)() = NULL; + void (*sig_handler)(int) = NULL; #endif #define MAIL_RET(val) \ diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 84984188f2710..06a3f916a849c 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -1247,8 +1247,8 @@ PHP_FUNCTION(proc_open) if (command_ht) { uint32_t num_elems = zend_hash_num_elements(command_ht); - if (num_elems == 0) { - zend_argument_value_error(1, "must have at least one element"); + if (UNEXPECTED(num_elems == 0)) { + zend_argument_must_not_be_empty_error(1); RETURN_THROWS(); } diff --git a/ext/standard/string.c b/ext/standard/string.c index b15a24a098faa..1e20791eb61ce 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -1273,10 +1273,10 @@ PHP_FUNCTION(str_increment) ZSTR_VAL(tmp)[0] = ZSTR_VAL(incremented)[0]; break; } - zend_string_release_ex(incremented, /* persistent */ false); - RETURN_STR(tmp); + zend_string_efree(incremented); + RETURN_NEW_STR(tmp); } - RETURN_STR(incremented); + RETURN_NEW_STR(incremented); } @@ -1323,17 +1323,17 @@ PHP_FUNCTION(str_decrement) if (UNEXPECTED(carry || (ZSTR_VAL(decremented)[0] == '0' && ZSTR_LEN(decremented) > 1))) { if (ZSTR_LEN(decremented) == 1) { - zend_string_release_ex(decremented, /* persistent */ false); + zend_string_efree(decremented); zend_argument_value_error(1, "\"%s\" is out of decrement range", ZSTR_VAL(str)); RETURN_THROWS(); } zend_string *tmp = zend_string_alloc(ZSTR_LEN(decremented) - 1, 0); memcpy(ZSTR_VAL(tmp), ZSTR_VAL(decremented) + 1, ZSTR_LEN(decremented) - 1); ZSTR_VAL(tmp)[ZSTR_LEN(decremented) - 1] = '\0'; - zend_string_release_ex(decremented, /* persistent */ false); - RETURN_STR(tmp); + zend_string_efree(decremented); + RETURN_NEW_STR(tmp); } - RETURN_STR(decremented); + RETURN_NEW_STR(decremented); } #if defined(PHP_WIN32) diff --git a/ext/standard/tests/array/array_map_variation4.phpt b/ext/standard/tests/array/array_map_variation4.phpt index 4d6269b3617db..d75a0bcf26108 100644 --- a/ext/standard/tests/array/array_map_variation4.phpt +++ b/ext/standard/tests/array/array_map_variation4.phpt @@ -17,9 +17,6 @@ function callback($a) $unset_var = 10; unset ($unset_var); -// get a resource variable -$fp = fopen(__FILE__, "r"); - // get a class class classA{ public function __toString(){ @@ -49,11 +46,11 @@ $arrays = array ( array("hello", $heredoc => "string"), // heredoc // array with object, unset variable and resource variable - array(@$unset_var => "hello", $fp => 'resource'), + array(@$unset_var => "hello", STDERR => 'resource'), // array with mixed values /*11*/ array('hello' => 1, "fruit" => 2.2, - $fp => 'resource', 133 => "int", + STDERR => 'resource', 133 => "int", @$unset_var => "unset", $heredoc => "heredoc") ); @@ -70,9 +67,9 @@ echo "Done"; --EXPECTF-- *** Testing array_map() : associative array with diff. keys for 'arr1' argument *** -Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d +Warning: Resource ID#3 used as offset, casting to integer (3) in %s on line %d -Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d +Warning: Resource ID#3 used as offset, casting to integer (3) in %s on line %d -- Iteration 1 -- array(0) { } @@ -131,7 +128,7 @@ array(2) { array(2) { [""]=> string(5) "hello" - [5]=> + [3]=> string(8) "resource" } -- Iteration 9 -- @@ -140,7 +137,7 @@ array(6) { int(1) ["fruit"]=> float(2.2) - [5]=> + [3]=> string(8) "resource" [133]=> string(3) "int" diff --git a/ext/standard/tests/array/array_reverse_variation4.phpt b/ext/standard/tests/array/array_reverse_variation4.phpt index 07454f5a1f261..4967f6e4dacb0 100644 --- a/ext/standard/tests/array/array_reverse_variation4.phpt +++ b/ext/standard/tests/array/array_reverse_variation4.phpt @@ -13,9 +13,6 @@ echo "*** Testing array_reverse() : usage variations ***\n"; $unset_var = 10; unset ($unset_var); -//get a resource variable -$fp = fopen(__FILE__, "r"); - //get a class class classA{ public function __toString(){ @@ -45,10 +42,10 @@ $arrays = array ( array("hello", $heredoc => "string"), // heredoc // array with object, unset variable and resource variable - array(@$unset_var => "hello", $fp => 'resource'), + array(@$unset_var => "hello", STDERR => 'resource'), // array with mixed values -/*11*/ array('hello' => 1, "fruit" => 2.2, $fp => 'resource', 133 => "int", @$unset_var => "unset", $heredoc => "heredoc") +/*11*/ array('hello' => 1, "fruit" => 2.2, STDERR => 'resource', 133 => "int", @$unset_var => "unset", $heredoc => "heredoc") ); // loop through the various elements of $arrays to test array_reverse() @@ -66,17 +63,14 @@ foreach($arrays as $array) { $iterator++; }; -// close the file resource used -fclose($fp); - echo "Done"; ?> --EXPECTF-- *** Testing array_reverse() : usage variations *** -Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d +Warning: Resource ID#3 used as offset, casting to integer (3) in %s on line %d -Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d +Warning: Resource ID#3 used as offset, casting to integer (3) in %s on line %d -- Iteration 1 -- - default argument - array(0) { @@ -259,7 +253,7 @@ array(2) { } - $preserve keys = true - array(2) { - [5]=> + [3]=> string(8) "resource" [""]=> string(5) "hello" @@ -295,7 +289,7 @@ array(6) { string(5) "unset" [133]=> string(3) "int" - [5]=> + [3]=> string(8) "resource" ["fruit"]=> float(2.2) diff --git a/ext/standard/tests/array/array_unique_variation3.phpt b/ext/standard/tests/array/array_unique_variation3.phpt index b412a19a422e5..91b551bb60402 100644 --- a/ext/standard/tests/array/array_unique_variation3.phpt +++ b/ext/standard/tests/array/array_unique_variation3.phpt @@ -13,9 +13,6 @@ echo "*** Testing array_unique() : assoc. array with diff. keys passed to \$inpu $unset_var = 10; unset ($unset_var); -// get a resource variable -$fp = fopen(__FILE__, "r"); - // get a class class classA { @@ -41,7 +38,7 @@ $inputs = array ( array("hello", $heredoc => "string", "string"), // array with object, unset variable and resource variable -/*8*/ array(@$unset_var => "hello", $fp => 'resource', 11, "hello"), +/*8*/ array(@$unset_var => "hello", STDERR => 'resource', 11, "hello"), ); // loop through each sub-array of $inputs to check the behavior of array_unique() @@ -52,14 +49,12 @@ foreach($inputs as $input) { $iterator++; } -fclose($fp); - echo "Done"; ?> --EXPECTF-- *** Testing array_unique() : assoc. array with diff. keys passed to $input argument *** -Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d +Warning: Resource ID#3 used as offset, casting to integer (3) in %s on line %d -- Iteration 1 -- array(1) { [0]=> @@ -103,9 +98,9 @@ array(2) { array(3) { [""]=> string(5) "hello" - [5]=> + [3]=> string(8) "resource" - [6]=> + [4]=> int(11) } Done diff --git a/ext/standard/tests/dir/closedir_variation2-win32-mb.phpt b/ext/standard/tests/dir/closedir_variation2-win32-mb.phpt index 9999cb8b10e51..1ada5b7fb36c5 100644 --- a/ext/standard/tests/dir/closedir_variation2-win32-mb.phpt +++ b/ext/standard/tests/dir/closedir_variation2-win32-mb.phpt @@ -47,5 +47,5 @@ NULL Directory Handle: resource(%d) of type (Unknown) -- Close directory handle second time: -- -closedir(): %s is not a valid Directory resource +closedir(): Argument #1 ($dir_handle) must be an open stream resource Directory Handle: resource(%d) of type (Unknown) diff --git a/ext/standard/tests/dir/closedir_variation2.phpt b/ext/standard/tests/dir/closedir_variation2.phpt index e4b782c255ce8..7898c9ae0ff13 100644 --- a/ext/standard/tests/dir/closedir_variation2.phpt +++ b/ext/standard/tests/dir/closedir_variation2.phpt @@ -41,5 +41,5 @@ NULL Directory Handle: resource(%d) of type (Unknown) -- Close directory handle second time: -- -closedir(): supplied resource is not a valid Directory resource +closedir(): Argument #1 ($dir_handle) must be an open stream resource Directory Handle: resource(%d) of type (Unknown) diff --git a/ext/standard/tests/dir/dir_basic-win32-mb.phpt b/ext/standard/tests/dir/dir_basic-win32-mb.phpt index 74e2cda6f070b..040596d40d6e7 100644 --- a/ext/standard/tests/dir/dir_basic-win32-mb.phpt +++ b/ext/standard/tests/dir/dir_basic-win32-mb.phpt @@ -85,5 +85,5 @@ object(Directory)#%d (2) { } Test read after closing the dir: -Directory::read(): %s is not a valid Directory resource +Directory::read(): cannot use Directory resource after it has been closed Done diff --git a/ext/standard/tests/dir/dir_basic.phpt b/ext/standard/tests/dir/dir_basic.phpt index d474122ba243b..17a2b42bcdaea 100644 --- a/ext/standard/tests/dir/dir_basic.phpt +++ b/ext/standard/tests/dir/dir_basic.phpt @@ -79,5 +79,5 @@ object(Directory)#%d (2) { } Test read after closing the dir: -Directory::read(): supplied resource is not a valid Directory resource +Directory::read(): cannot use Directory resource after it has been closed Done diff --git a/ext/standard/tests/dir/rewinddir_variation2-win32-mb.phpt b/ext/standard/tests/dir/rewinddir_variation2-win32-mb.phpt index ab639c7f24f3c..4bd69b61ff7d6 100644 --- a/ext/standard/tests/dir/rewinddir_variation2-win32-mb.phpt +++ b/ext/standard/tests/dir/rewinddir_variation2-win32-mb.phpt @@ -42,4 +42,4 @@ resource(%d) of type (stream) string(%d) "%s" -- Call to rewinddir() -- -rewinddir(): %s is not a valid Directory resource +rewinddir(): Argument #1 ($dir_handle) must be an open stream resource diff --git a/ext/standard/tests/dir/rewinddir_variation2.phpt b/ext/standard/tests/dir/rewinddir_variation2.phpt index 654c68cecbe01..7ce3c522352d7 100644 --- a/ext/standard/tests/dir/rewinddir_variation2.phpt +++ b/ext/standard/tests/dir/rewinddir_variation2.phpt @@ -36,4 +36,4 @@ resource(%d) of type (stream) string(%d) "%s" -- Call to rewinddir() -- -rewinddir(): supplied resource is not a valid Directory resource +rewinddir(): Argument #1 ($dir_handle) must be an open stream resource diff --git a/ext/standard/tests/directory/DirectoryClass_readonly_handle_by_pass_via_ArrayObject.phpt b/ext/standard/tests/directory/DirectoryClass_readonly_handle_by_pass_via_ArrayObject.phpt new file mode 100644 index 0000000000000..91416f2c71202 --- /dev/null +++ b/ext/standard/tests/directory/DirectoryClass_readonly_handle_by_pass_via_ArrayObject.phpt @@ -0,0 +1,34 @@ +--TEST-- +Changing Directory::$handle property +--FILE-- +getMessage(), PHP_EOL; +} +var_dump($d->handle); + +try { + $s = $d->read(); + var_dump($s); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +try { + unset($ao['handle']); + var_dump($d->handle); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +resource(3) of type (stream) +Error: Internal directory stream has been altered +Error: Typed property Directory::$handle must not be accessed before initialization diff --git a/ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt b/ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt index 35b07591635fd..95999581f31c9 100644 --- a/ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt +++ b/ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt @@ -27,4 +27,4 @@ object(Directory)#2 (0) { ["handle"]=> uninitialized(mixed) } -Error: Unable to find my handle property +Error: Internal directory stream has been altered diff --git a/ext/standard/tests/file/007_basic.phpt b/ext/standard/tests/file/007_basic.phpt index 37047ec32b28b..6a0c918ea39c8 100644 --- a/ext/standard/tests/file/007_basic.phpt +++ b/ext/standard/tests/file/007_basic.phpt @@ -102,8 +102,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'wb' -- resource(%d) of type (stream) @@ -111,8 +111,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'wt' -- resource(%d) of type (stream) @@ -120,8 +120,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'w+' -- resource(%d) of type (stream) @@ -129,8 +129,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'w+b' -- resource(%d) of type (stream) @@ -138,8 +138,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'w+t' -- resource(%d) of type (stream) @@ -147,8 +147,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'r' -- resource(%d) of type (stream) @@ -156,8 +156,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'rb' -- resource(%d) of type (stream) @@ -165,8 +165,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'rt' -- resource(%d) of type (stream) @@ -174,8 +174,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'r+' -- resource(%d) of type (stream) @@ -183,8 +183,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'r+b' -- resource(%d) of type (stream) @@ -192,8 +192,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'r+t' -- resource(%d) of type (stream) @@ -201,8 +201,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'a' -- resource(%d) of type (stream) @@ -210,8 +210,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'ab' -- resource(%d) of type (stream) @@ -219,8 +219,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'at' -- resource(%d) of type (stream) @@ -228,8 +228,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'a+' -- resource(%d) of type (stream) @@ -237,8 +237,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'a+t' -- resource(%d) of type (stream) @@ -246,8 +246,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'a+b' -- resource(%d) of type (stream) @@ -255,8 +255,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource -- Iteration with mode 'x' -- resource(%d) of type (stream) @@ -264,8 +264,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource resource(%d) of type (Unknown) -- Iteration with mode 'xb' -- @@ -274,8 +274,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource resource(%d) of type (Unknown) -- Iteration with mode 'xt' -- @@ -284,8 +284,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource resource(%d) of type (Unknown) -- Iteration with mode 'x+' -- @@ -294,8 +294,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource resource(%d) of type (Unknown) -- Iteration with mode 'x+b' -- @@ -304,8 +304,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource resource(%d) of type (Unknown) -- Iteration with mode 'x+t' -- @@ -314,8 +314,8 @@ int(0) bool(false) bool(true) resource(%d) of type (Unknown) -ftell(): supplied resource is not a valid stream resource -feof(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource +feof(): Argument #1 ($stream) must be an open stream resource resource(%d) of type (Unknown) *** Done *** diff --git a/ext/standard/tests/file/bug72666_variation3.phpt b/ext/standard/tests/file/bug72666_variation3.phpt index a491640c4f746..7937bd904ad7d 100644 --- a/ext/standard/tests/file/bug72666_variation3.phpt +++ b/ext/standard/tests/file/bug72666_variation3.phpt @@ -5,23 +5,11 @@ Bug #72666 (stat cache clearing inconsistent - plain wrapper) $filename = __DIR__ . '/bug72666_variation3.txt'; file_put_contents($filename, "test"); -$fd = fopen($filename, "r"); -$atime1 = fileatime($filename); -sleep(1); -var_dump(fread($fd, 4)); -$atime2 = fileatime($filename); $mtime1 = filemtime($filename); -fclose($fd); $fd = fopen($filename, "w"); sleep(1); var_dump(fwrite($fd, "data")); $mtime2 = filemtime($filename); -if (substr(PHP_OS, 0, 3) == 'WIN') { - // Windows do not hundle atime - var_dump($atime2 == $atime1); -} else { - var_dump($atime2 > $atime1); -} var_dump($mtime2 > $mtime1); ?> --CLEAN-- @@ -29,7 +17,5 @@ var_dump($mtime2 > $mtime1); unlink(__DIR__ . '/bug72666_variation3.txt'); ?> --EXPECT-- -string(4) "test" int(4) bool(true) -bool(true) diff --git a/ext/standard/tests/file/fclose_variation1.phpt b/ext/standard/tests/file/fclose_variation1.phpt index 5f6c25860d64f..56a6d4bd4c1c4 100644 --- a/ext/standard/tests/file/fclose_variation1.phpt +++ b/ext/standard/tests/file/fclose_variation1.phpt @@ -15,6 +15,6 @@ try { echo "\nDone.\n"; ?> --EXPECT-- -fread(): supplied resource is not a valid stream resource +fread(): Argument #1 ($stream) must be an open stream resource Done. diff --git a/ext/standard/tests/file/feof_basic.phpt b/ext/standard/tests/file/feof_basic.phpt index a263bf1fbe6c4..943af213e39a2 100644 --- a/ext/standard/tests/file/feof_basic.phpt +++ b/ext/standard/tests/file/feof_basic.phpt @@ -94,5 +94,5 @@ bool(false) *** testing feof after a seek passed the end *** bool(false) *** closing file, testing eof *** -feof(): supplied resource is not a valid stream resource +feof(): Argument #1 ($stream) must be an open stream resource Done diff --git a/ext/standard/tests/file/fgetc_variation2.phpt b/ext/standard/tests/file/fgetc_variation2.phpt index 42558998337ed..89161d0881902 100644 --- a/ext/standard/tests/file/fgetc_variation2.phpt +++ b/ext/standard/tests/file/fgetc_variation2.phpt @@ -30,5 +30,5 @@ echo "Done"; --EXPECT-- *** Testing fgetc() : usage variations *** -- Testing fgetc() with closed handle -- -fgetc(): supplied resource is not a valid stream resource +fgetc(): Argument #1 ($stream) must be an open stream resource Done diff --git a/ext/standard/tests/file/fgets_variation2.phpt b/ext/standard/tests/file/fgets_variation2.phpt index 28cba347d5ff7..5d262cde295b4 100644 --- a/ext/standard/tests/file/fgets_variation2.phpt +++ b/ext/standard/tests/file/fgets_variation2.phpt @@ -35,6 +35,6 @@ echo "Done"; --EXPECT-- *** Testing fgets() : usage variations *** -- Testing fgets() with closed handle -- -fgets(): supplied resource is not a valid stream resource -fgets(): supplied resource is not a valid stream resource +fgets(): Argument #1 ($stream) must be an open stream resource +fgets(): Argument #1 ($stream) must be an open stream resource Done diff --git a/ext/standard/tests/file/file_get_contents_basic.phpt b/ext/standard/tests/file/file_get_contents_basic.phpt index 96f74c7611917..cf5e4ba6165d8 100644 --- a/ext/standard/tests/file/file_get_contents_basic.phpt +++ b/ext/standard/tests/file/file_get_contents_basic.phpt @@ -29,6 +29,7 @@ echo "\n*** Done ***"; $file_path = __DIR__; include($file_path."/file.inc"); delete_files($file_path, 1); +@unlink($file_path."/file_get_contents_basic1.tmp"); ?> --EXPECT-- *** Testing the basic functionality of the file_get_contents() function *** diff --git a/ext/standard/tests/file/flock.phpt b/ext/standard/tests/file/flock.phpt index 346029c7cab27..a3c1804584023 100644 --- a/ext/standard/tests/file/flock.phpt +++ b/ext/standard/tests/file/flock.phpt @@ -46,7 +46,7 @@ $file = __DIR__."/flock.dat"; unlink($file); ?> --EXPECT-- -flock(): supplied resource is not a valid stream resource +flock(): Argument #1 ($stream) must be an open stream resource bool(true) bool(true) bool(true) diff --git a/ext/standard/tests/file/flock_error.phpt b/ext/standard/tests/file/flock_error.phpt index 753aaa6fb34e8..2ca20c3436ab6 100644 --- a/ext/standard/tests/file/flock_error.phpt +++ b/ext/standard/tests/file/flock_error.phpt @@ -70,4 +70,4 @@ flock(): Argument #2 ($operation) must be of type int, string given flock(): Argument #2 ($operation) must be of type int, string given --- Iteration 7 --- flock(): Argument #2 ($operation) must be of type int, string given -flock(): supplied resource is not a valid stream resource +flock(): Argument #1 ($stream) must be an open stream resource diff --git a/ext/standard/tests/file/fseek_ftell_rewind_error1.phpt b/ext/standard/tests/file/fseek_ftell_rewind_error1.phpt index d576403644546..c38f7905399be 100644 --- a/ext/standard/tests/file/fseek_ftell_rewind_error1.phpt +++ b/ext/standard/tests/file/fseek_ftell_rewind_error1.phpt @@ -20,5 +20,5 @@ echo "Done\n"; --EXPECT-- *** Testing fseek() : error conditions *** -- Testing fseek() with closed/unset file handle -- -fseek(): supplied resource is not a valid stream resource +fseek(): Argument #1 ($stream) must be an open stream resource Done diff --git a/ext/standard/tests/file/fseek_ftell_rewind_error2.phpt b/ext/standard/tests/file/fseek_ftell_rewind_error2.phpt index 5a947f66587fe..58c3b5330d874 100644 --- a/ext/standard/tests/file/fseek_ftell_rewind_error2.phpt +++ b/ext/standard/tests/file/fseek_ftell_rewind_error2.phpt @@ -20,5 +20,5 @@ echo "Done\n"; --EXPECT-- *** Testing ftell() : error conditions *** -- Testing ftell with closed/unset file handle -- -ftell(): supplied resource is not a valid stream resource +ftell(): Argument #1 ($stream) must be an open stream resource Done diff --git a/ext/standard/tests/file/fseek_ftell_rewind_error3.phpt b/ext/standard/tests/file/fseek_ftell_rewind_error3.phpt index f4212ec71b427..ad50244edb3e4 100644 --- a/ext/standard/tests/file/fseek_ftell_rewind_error3.phpt +++ b/ext/standard/tests/file/fseek_ftell_rewind_error3.phpt @@ -20,5 +20,5 @@ echo "Done\n"; --EXPECT-- *** Testing rewind() : error conditions *** -- Testing rewind() with closed/unset file handle -- -rewind(): supplied resource is not a valid stream resource +rewind(): Argument #1 ($stream) must be an open stream resource Done diff --git a/ext/standard/tests/file/fstat.phpt b/ext/standard/tests/file/fstat.phpt index b48b06cfe50b9..86d1453f1b728 100644 --- a/ext/standard/tests/file/fstat.phpt +++ b/ext/standard/tests/file/fstat.phpt @@ -72,5 +72,5 @@ array(26) { ["blocks"]=> int(%i) } -fstat(): supplied resource is not a valid stream resource +fstat(): Argument #1 ($stream) must be an open stream resource Done diff --git a/ext/standard/tests/file/ftruncate_error.phpt b/ext/standard/tests/file/ftruncate_error.phpt index 752397a461d6f..3397fc25f44ad 100644 --- a/ext/standard/tests/file/ftruncate_error.phpt +++ b/ext/standard/tests/file/ftruncate_error.phpt @@ -35,6 +35,6 @@ unlink( $filename ); Initial file size = 36 -- Testing ftruncate() with closed/unset file handle -- -ftruncate(): supplied resource is not a valid stream resource +ftruncate(): Argument #1 ($stream) must be an open stream resource int(36) Done diff --git a/ext/standard/tests/file/fwrite.phpt b/ext/standard/tests/file/fwrite.phpt index 1494ea7a0f5e8..12bfb6727ec31 100644 --- a/ext/standard/tests/file/fwrite.phpt +++ b/ext/standard/tests/file/fwrite.phpt @@ -17,12 +17,6 @@ var_dump(fwrite($fp, "data", -1)); var_dump(fwrite($fp, "data", 100000)); fclose($fp); -try { - var_dump(fwrite($fp, "data", -1)); -} catch (Throwable $e) { - echo $e::class, ': ', $e->getMessage(), PHP_EOL; -} - var_dump(file_get_contents($filename)); echo "Done\n"; @@ -39,6 +33,5 @@ Notice: fwrite(): Write of 4 bytes failed with errno=9 Bad file descriptor in %s bool(false) int(0) int(4) -TypeError: fwrite(): supplied resource is not a valid stream resource string(4) "data" Done diff --git a/ext/standard/tests/file/fwrite_error.phpt b/ext/standard/tests/file/fwrite_error.phpt index d24f7b8084cf0..62ec928a29dfc 100644 --- a/ext/standard/tests/file/fwrite_error.phpt +++ b/ext/standard/tests/file/fwrite_error.phpt @@ -40,5 +40,5 @@ unlink( $filename ); int(0) int(0) -- Testing fwrite() with closed/unset file handle -- -fwrite(): supplied resource is not a valid stream resource +fwrite(): Argument #1 ($stream) must be an open stream resource Done diff --git a/ext/standard/tests/file/gh18212.phpt b/ext/standard/tests/file/gh18212.phpt new file mode 100644 index 0000000000000..6e4d8ad9bd328 --- /dev/null +++ b/ext/standard/tests/file/gh18212.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-18212: fseek with SEEK_CUR and negative offset leads to negative file stream position. +--FILE-- + +--EXPECT-- +int(-1) +int(-1) + diff --git a/ext/standard/tests/file/stream_rfc2397_007.phpt b/ext/standard/tests/file/stream_rfc2397_007.phpt index dcbe5beeb3dc9..49a037e855fbd 100644 --- a/ext/standard/tests/file/stream_rfc2397_007.phpt +++ b/ext/standard/tests/file/stream_rfc2397_007.phpt @@ -118,7 +118,7 @@ int(2) bool(false) ===S:-10,C=== int(-1) -bool(false) +int(2) bool(false) ===S:3,S=== int(0) diff --git a/ext/standard/tests/file/stream_supports_lock.phpt b/ext/standard/tests/file/stream_supports_lock.phpt index 0d2f04b72d9aa..76249e9106ee4 100644 --- a/ext/standard/tests/file/stream_supports_lock.phpt +++ b/ext/standard/tests/file/stream_supports_lock.phpt @@ -44,5 +44,5 @@ bool(false) resource(%d) of type (stream) bool(false) resource(%d) of type (stream-context) -stream_supports_lock(): supplied resource is not a valid stream resource +stream_supports_lock(): Argument #1 ($stream) must be an open stream resource Done diff --git a/ext/standard/tests/file/userstreams_004.phpt b/ext/standard/tests/file/userstreams_004.phpt index 959f02f5b1cd7..fa68e5aa9307a 100644 --- a/ext/standard/tests/file/userstreams_004.phpt +++ b/ext/standard/tests/file/userstreams_004.phpt @@ -19,7 +19,7 @@ class test_wrapper extends test_wrapper_base { } function test($name, $fd, $mode) { echo "------ $name: -------\n"; - flock($fd, $mode); + (void)flock($fd, $mode); $data = stream_get_meta_data($fd); var_dump($data['wrapper_data']->mode === $mode); } diff --git a/ext/standard/tests/filters/bug54350.phpt b/ext/standard/tests/filters/bug54350.phpt index a017893eed7bb..046db0483a9ae 100644 --- a/ext/standard/tests/filters/bug54350.phpt +++ b/ext/standard/tests/filters/bug54350.phpt @@ -22,5 +22,5 @@ fwrite($fd, "foo"); ?> --EXPECTF-- -Warning: fclose(): 5 is not a valid stream resource in %s on line %d -fclose(): supplied resource is not a valid stream resource +Warning: fclose(): cannot close the provided stream, as it must not be manually closed in %s on line %d +fclose(): Argument #1 ($stream) must be an open stream resource diff --git a/ext/standard/tests/general_functions/bug73973.phpt b/ext/standard/tests/general_functions/bug73973.phpt index 8bb4daaab094d..fccd8b5af9457 100644 --- a/ext/standard/tests/general_functions/bug73973.phpt +++ b/ext/standard/tests/general_functions/bug73973.phpt @@ -6,4 +6,4 @@ define('myerr', fopen('php://stderr', 'w')); debug_zval_dump(myerr); ?> --EXPECTF-- -resource(5) of type (stream) refcount(%d) +resource(%d) of type (stream) refcount(%d) diff --git a/ext/standard/tests/general_functions/floatval.phpt b/ext/standard/tests/general_functions/floatval.phpt index f9aa74e342d56..9ff49bb01084e 100644 --- a/ext/standard/tests/general_functions/floatval.phpt +++ b/ext/standard/tests/general_functions/floatval.phpt @@ -47,18 +47,11 @@ foreach ($valid_floats as $value ) { echo "\n*** Testing floatval() on non floating types ***\n"; -// get a resource type variable -$fp = fopen (__FILE__, "r"); -fclose($fp); -$dfp = opendir ( __DIR__ ); -closedir($dfp); - // other types in an array $not_float_types = array ( -2147483648, // max negative integer value 2147483648, // max positive integer value - $fp, // resource - $dfp, + STDERR, // resource "0.0", // string "1.0", "-1.3e3", @@ -89,7 +82,6 @@ foreach ($not_float_types as $type ) { echo "\nDone\n"; - ?> --EXPECTF-- *** Testing floatval() with valid float values *** @@ -145,8 +137,7 @@ Warning: A non-numeric value encountered in %s on line %d Warning: A non-numeric value encountered in %s on line %d float(-2147483648) float(2147483648) -float(5) -float(6) +float(3) float(0) float(1) float(-1300) @@ -163,8 +154,7 @@ float(0) *** Testing doubleval() on non floating types *** float(-2147483648) float(2147483648) -float(5) -float(6) +float(3) float(0) float(1) float(-1300) diff --git a/ext/standard/tests/general_functions/floatval_variation1.phpt b/ext/standard/tests/general_functions/floatval_variation1.phpt index 856e4e31ebb0d..032d089b01c49 100644 --- a/ext/standard/tests/general_functions/floatval_variation1.phpt +++ b/ext/standard/tests/general_functions/floatval_variation1.phpt @@ -2,18 +2,12 @@ Testing floatval() and its alias doubleval() functions : usage variations - different data types as $y arg --FILE-- -2147483648, // max negative integer value "2147483647" => 2147483648, // max positive integer value - "file resoruce" => $fp, - "directory resource" => $dfp, + "stream resource" => STDERR, "\"0.0\"" => "0.0", // string "\"1.0\"" => "1.0", "\"-1.3e3\"" => "-1.3e3", @@ -24,7 +18,6 @@ $not_float_types = array ( "\"10.0 dollar\" + 1.0" => "10.0 dollar" + 1.0, "\"\"" => "", "true" => true, - "NULL" => NULL, "null" => null, ); /* loop through the $not_float_types to see working of @@ -57,11 +50,8 @@ float(-2147483648) -- Iteration : 2147483647 -- float(2147483648) --- Iteration : file resoruce -- -float(5) - --- Iteration : directory resource -- -float(6) +-- Iteration : stream resource -- +float(3) -- Iteration : "0.0" -- float(0) @@ -93,9 +83,6 @@ float(0) -- Iteration : true -- float(1) --- Iteration : NULL -- -float(0) - -- Iteration : null -- float(0) @@ -107,11 +94,8 @@ float(-2147483648) -- Iteration : 2147483647 -- float(2147483648) --- Iteration : file resoruce -- -float(5) - --- Iteration : directory resource -- -float(6) +-- Iteration : stream resource -- +float(3) -- Iteration : "0.0" -- float(0) @@ -143,8 +127,5 @@ float(0) -- Iteration : true -- float(1) --- Iteration : NULL -- -float(0) - -- Iteration : null -- float(0) diff --git a/ext/standard/tests/general_functions/print_r.phpt b/ext/standard/tests/general_functions/print_r.phpt deleted file mode 100644 index 0ea60658aed7a..0000000000000 --- a/ext/standard/tests/general_functions/print_r.phpt +++ /dev/null @@ -1,1696 +0,0 @@ ---TEST-- -Test print_r() function ---INI-- -precision=14 ---FILE-- - 'One'), - array("test" => "is_array"), - array(0), - array(-1), - array(10.5, 5.6), - array("string", "test"), - array('string', 'test'), -); -/* calling check_printr() to display contents of $arrays */ -check_printr($arrays); - -echo "\n*** Testing print_r() on object variables ***\n"; -#[AllowDynamicProperties] -class object_class -{ - var $value; - public $public_var1 = 10; - private $private_var1 = 20; - private $private_var2; - protected $protected_var1 = "string_1"; - protected $protected_var2; - - function __construct() { - $this->value = 50; - $this->public_var2 = 11; - $this->private_var2 = 21; - $this->protected_var2 = "string_2"; - } - - public function foo1() { - echo "foo1() is called\n"; - } - protected function foo2() { - echo "foo2() is called\n"; - } - private function foo3() { - echo "foo3() is called\n"; - } -} -/* class with no member */ -class no_member_class { - // no members -} - -/* class with member as object of other class */ -#[AllowDynamicProperties] -class contains_object_class -{ - var $p = 30; - var $class_object1; - public $class_object2; - private $class_object3; - protected $class_object4; - var $no_member_class_object; - - public function func() { - echo "func() is called \n"; - } - - function __construct() { - $this->class_object1 = new object_class(); - $this->class_object2 = new object_class(); - $this->class_object3 = $this->class_object1; - $this->class_object4 = $this->class_object2; - $this->no_member_class_object = new no_member_class(); - $this->class_object5 = $this; //recursive reference - } -} - -/* objects of different classes */ -$obj = new contains_object_class; -$temp_class_obj = new object_class(); - -/* object which is unset */ -$unset_obj = new object_class(); -unset($unset_obj); - -$objects = array ( - new object_class, - new no_member_class, - new contains_object_class, - $obj, - $obj->class_object1, - $obj->class_object2, - $obj->no_member_class_object, - $temp_class_obj, - @$unset_obj -); -/* calling check_printr() to display contents of the objects using print_r() */ -check_printr($objects); - -echo "\n** Testing print_r() on objects having circular reference **\n"; -$recursion_obj1 = new object_class(); -$recursion_obj2 = new object_class(); -$recursion_obj1->obj = &$recursion_obj2; //circular reference -$recursion_obj2->obj = &$recursion_obj1; //circular reference -print_r($recursion_obj2); - -echo "\n*** Testing print_r() on resources ***\n"; -/* file type resource */ -$file_handle = fopen(__FILE__, "r"); - -/* directory type resource */ -$dir_handle = opendir( __DIR__ ); - -$resources = array ( - $file_handle, - $dir_handle -); -/* calling check_printr() to display the resource content type - using print_r() */ -check_printr($resources); - -echo "\n*** Testing print_r() on different combinations of scalar - and non-scalar variables ***\n"; -/* a variable which is unset */ -$unset_var = 10.5; -unset($unset_var); - -/* unset file type resource */ -unset($file_handle); - -$variations = array ( - array( 123, -1.2345, "a" ), - array( "d", array(1, 3, 5), true, null), - array( new no_member_class, array(), false, 0 ), - array( -0.00, "Where am I?", array(7,8,9), TRUE, 'A', 987654321 ), - array( @$unset_var, 2.E+10, 100-20.9, 000004.599998 ), //unusual data - array( "array(1,2,3,4)1.0000002TRUE", @$file_handle, 111333.00+45e5, '/00\7') -); -/* calling check_printr() to display combinations of scalar and - non-scalar variables using print_r() */ -check_printr($variations); - -echo "\n*** Testing print_r() on miscellaneous input arguments ***\n"; -$misc_values = array ( - @$unset_var, - NULL, // NULL argument - @$undef_variable, //undefined variable - null -); -/* calling check_printr() to display miscellaneous data using print_r() */ -check_printr($misc_values); - -/* closing resource handle used */ -closedir($dir_handle); - -echo "Done\n"; -?> ---EXPECTF-- -*** Testing print_r() on integer variables *** - --- Iteration 1 -- -0 -0 -0 --- Iteration 2 -- -83 -83 -83 --- Iteration 3 -- -123000000 -123000000 -123000000 --- Iteration 4 -- --83 --83 --83 --- Iteration 5 -- --12300000 --12300000 --12300000 --- Iteration 6 -- -Array -( - [0] => 1 - [1] => 2 - [2] => 3 - [3] => 4 - [4] => 5 - [5] => 6 - [6] => 7 - [7] => 8 - [8] => 9 - [9] => 10 -) - -Array -( - [0] => 1 - [1] => 2 - [2] => 3 - [3] => 4 - [4] => 5 - [5] => 6 - [6] => 7 - [7] => 8 - [8] => 9 - [9] => 10 -) - -Array -( - [0] => 1 - [1] => 2 - [2] => 3 - [3] => 4 - [4] => 5 - [5] => 6 - [6] => 7 - [7] => 8 - [8] => 9 - [9] => 10 -) - --- Iteration 7 -- -Array -( - [0] => -1 - [1] => -2 - [2] => -3 - [3] => -4 - [4] => -5 - [5] => -6 - [6] => -7 - [7] => -8 - [8] => -9 - [9] => -10 -) - -Array -( - [0] => -1 - [1] => -2 - [2] => -3 - [3] => -4 - [4] => -5 - [5] => -6 - [6] => -7 - [7] => -8 - [8] => -9 - [9] => -10 -) - -Array -( - [0] => -1 - [1] => -2 - [2] => -3 - [3] => -4 - [4] => -5 - [5] => -6 - [6] => -7 - [7] => -8 - [8] => -9 - [9] => -10 -) - --- Iteration 8 -- -2147483647 -2147483647 -2147483647 --- Iteration 9 -- -2147483648 -2147483648 -2147483648 --- Iteration 10 -- --2147483648 --2147483648 --2147483648 --- Iteration 11 -- --2147483647 --2147483647 --2147483647 --- Iteration 12 -- -2147483647 -2147483647 -2147483647 --- Iteration 13 -- --2147483648 --2147483648 --2147483648 --- Iteration 14 -- -2147483647 -2147483647 -2147483647 --- Iteration 15 -- --2147483648 --2147483648 --2147483648 -*** Testing print_r() on float variables *** - --- Iteration 1 -- --0 --0 --0 --- Iteration 2 -- -0 -0 -0 --- Iteration 3 -- -1.234 -1.234 -1.234 --- Iteration 4 -- --1.234 --1.234 --1.234 --- Iteration 5 -- --2 --2 --2 --- Iteration 6 -- -2 -2 -2 --- Iteration 7 -- --0.5 --0.5 --0.5 --- Iteration 8 -- -0.567 -0.567 -0.567 --- Iteration 9 -- --0.00067 --0.00067 --0.00067 --- Iteration 10 -- --670 --670 --670 --- Iteration 11 -- -670 -670 -670 --- Iteration 12 -- -670 -670 -670 --- Iteration 13 -- --0.00410003 --0.00410003 --0.00410003 --- Iteration 14 -- --4100.03 --4100.03 --4100.03 --- Iteration 15 -- -0.004100003 -0.004100003 -0.004100003 --- Iteration 16 -- -4100.003 -4100.003 -4100.003 --- Iteration 17 -- -100000 -100000 -100000 --- Iteration 18 -- --100000 --100000 --100000 --- Iteration 19 -- -1.0E-5 -1.0E-5 -1.0E-5 --- Iteration 20 -- --1.0E-5 --1.0E-5 --1.0E-5 --- Iteration 21 -- -100000 -100000 -100000 --- Iteration 22 -- --100000 --100000 --100000 --- Iteration 23 -- -100000 -100000 -100000 --- Iteration 24 -- --100000 --100000 --100000 --- Iteration 25 -- -100000 -100000 -100000 --- Iteration 26 -- --100000 --100000 --100000 --- Iteration 27 -- -1.0E-5 -1.0E-5 -1.0E-5 --- Iteration 28 -- --1.0E-5 --1.0E-5 --1.0E-5 --- Iteration 29 -- --2147483649 --2147483649 --2147483649 --- Iteration 30 -- -2147483649 -2147483649 -2147483649 --- Iteration 31 -- -2147483649 -2147483649 -2147483649 --- Iteration 32 -- --2147483649 --2147483649 --2147483649 -*** Testing print_r() on string variables *** - --- Iteration 1 -- - - - --- Iteration 2 -- - - - --- Iteration 3 -- - - - --- Iteration 4 -- - - - --- Iteration 5 -- -0 -0 -0 --- Iteration 6 -- -%0 -%0 -%0 --- Iteration 7 -- -\0 -\0 -\0 --- Iteration 8 -- - - - --- Iteration 9 -- -\t -\t -\t --- Iteration 10 -- -PHP -PHP -PHP --- Iteration 11 -- -PHP -PHP -PHP --- Iteration 12 -- -abcd%0n1234%005678%000efgh\xijkl -abcd%0n1234%005678%000efgh\xijkl -abcd%0n1234%005678%000efgh\xijkl --- Iteration 13 -- -abcd%0efgh%0ijkl%0mnop%00qrst%0uvwx%00yz -abcd%0efgh%0ijkl%0mnop%00qrst%0uvwx%00yz -abcd%0efgh%0ijkl%0mnop%00qrst%0uvwx%00yz --- Iteration 14 -- -1234 -5678 - 9100"abcda -1234 -5678 - 9100"abcda -1234 -5678 - 9100"abcda -*** Testing print_r() on boolean variables *** - --- Iteration 1 -- -1 -1 -1 --- Iteration 2 -- - - - --- Iteration 3 -- -1 -1 -1 --- Iteration 4 -- - - -bool(true) - -bool(true) - -*** Testing print_r() on array variables *** - --- Iteration 1 -- -Array -( -) - -Array -( -) - -Array -( -) - --- Iteration 2 -- -Array -( - [0] => -) - -Array -( - [0] => -) - -Array -( - [0] => -) - --- Iteration 3 -- -Array -( - [0] => -) - -Array -( - [0] => -) - -Array -( - [0] => -) - --- Iteration 4 -- -Array -( - [0] => 1 -) - -Array -( - [0] => 1 -) - -Array -( - [0] => 1 -) - --- Iteration 5 -- -Array -( - [0] => -) - -Array -( - [0] => -) - -Array -( - [0] => -) - --- Iteration 6 -- -Array -( - [0] => -) - -Array -( - [0] => -) - -Array -( - [0] => -) - --- Iteration 7 -- -Array -( - [0] => Array - ( - ) - - [1] => Array - ( - ) - -) - -Array -( - [0] => Array - ( - ) - - [1] => Array - ( - ) - -) - -Array -( - [0] => Array - ( - ) - - [1] => Array - ( - ) - -) - --- Iteration 8 -- -Array -( - [0] => Array - ( - [0] => 1 - [1] => 2 - ) - - [1] => Array - ( - [0] => a - [1] => b - ) - -) - -Array -( - [0] => Array - ( - [0] => 1 - [1] => 2 - ) - - [1] => Array - ( - [0] => a - [1] => b - ) - -) - -Array -( - [0] => Array - ( - [0] => 1 - [1] => 2 - ) - - [1] => Array - ( - [0] => a - [1] => b - ) - -) - --- Iteration 9 -- -Array -( - [1] => One -) - -Array -( - [1] => One -) - -Array -( - [1] => One -) - --- Iteration 10 -- -Array -( - [test] => is_array -) - -Array -( - [test] => is_array -) - -Array -( - [test] => is_array -) - --- Iteration 11 -- -Array -( - [0] => 0 -) - -Array -( - [0] => 0 -) - -Array -( - [0] => 0 -) - --- Iteration 12 -- -Array -( - [0] => -1 -) - -Array -( - [0] => -1 -) - -Array -( - [0] => -1 -) - --- Iteration 13 -- -Array -( - [0] => 10.5 - [1] => 5.6 -) - -Array -( - [0] => 10.5 - [1] => 5.6 -) - -Array -( - [0] => 10.5 - [1] => 5.6 -) - --- Iteration 14 -- -Array -( - [0] => string - [1] => test -) - -Array -( - [0] => string - [1] => test -) - -Array -( - [0] => string - [1] => test -) - --- Iteration 15 -- -Array -( - [0] => string - [1] => test -) - -Array -( - [0] => string - [1] => test -) - -Array -( - [0] => string - [1] => test -) - -*** Testing print_r() on object variables *** - --- Iteration 1 -- -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - --- Iteration 2 -- -no_member_class Object -( -) - -no_member_class Object -( -) - -no_member_class Object -( -) - --- Iteration 3 -- -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - --- Iteration 4 -- -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - --- Iteration 5 -- -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - --- Iteration 6 -- -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - --- Iteration 7 -- -no_member_class Object -( -) - -no_member_class Object -( -) - -no_member_class Object -( -) - --- Iteration 8 -- -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - --- Iteration 9 -- - - - -** Testing print_r() on objects having circular reference ** -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - [obj] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - [obj] => object_class Object - *RECURSION* - ) - -) - -*** Testing print_r() on resources *** - --- Iteration 1 -- -Resource id #5 -Resource id #5 -Resource id #5 --- Iteration 2 -- -Resource id #6 -Resource id #6 -Resource id #6 -*** Testing print_r() on different combinations of scalar - and non-scalar variables *** - --- Iteration 1 -- -Array -( - [0] => 123 - [1] => -1.2345 - [2] => a -) - -Array -( - [0] => 123 - [1] => -1.2345 - [2] => a -) - -Array -( - [0] => 123 - [1] => -1.2345 - [2] => a -) - --- Iteration 2 -- -Array -( - [0] => d - [1] => Array - ( - [0] => 1 - [1] => 3 - [2] => 5 - ) - - [2] => 1 - [3] => -) - -Array -( - [0] => d - [1] => Array - ( - [0] => 1 - [1] => 3 - [2] => 5 - ) - - [2] => 1 - [3] => -) - -Array -( - [0] => d - [1] => Array - ( - [0] => 1 - [1] => 3 - [2] => 5 - ) - - [2] => 1 - [3] => -) - --- Iteration 3 -- -Array -( - [0] => no_member_class Object - ( - ) - - [1] => Array - ( - ) - - [2] => - [3] => 0 -) - -Array -( - [0] => no_member_class Object - ( - ) - - [1] => Array - ( - ) - - [2] => - [3] => 0 -) - -Array -( - [0] => no_member_class Object - ( - ) - - [1] => Array - ( - ) - - [2] => - [3] => 0 -) - --- Iteration 4 -- -Array -( - [0] => -0 - [1] => Where am I? - [2] => Array - ( - [0] => 7 - [1] => 8 - [2] => 9 - ) - - [3] => 1 - [4] => A - [5] => 987654321 -) - -Array -( - [0] => -0 - [1] => Where am I? - [2] => Array - ( - [0] => 7 - [1] => 8 - [2] => 9 - ) - - [3] => 1 - [4] => A - [5] => 987654321 -) - -Array -( - [0] => -0 - [1] => Where am I? - [2] => Array - ( - [0] => 7 - [1] => 8 - [2] => 9 - ) - - [3] => 1 - [4] => A - [5] => 987654321 -) - --- Iteration 5 -- -Array -( - [0] => - [1] => 20000000000 - [2] => 79.1 - [3] => 4.599998 -) - -Array -( - [0] => - [1] => 20000000000 - [2] => 79.1 - [3] => 4.599998 -) - -Array -( - [0] => - [1] => 20000000000 - [2] => 79.1 - [3] => 4.599998 -) - --- Iteration 6 -- -Array -( - [0] => array(1,2,3,4)1.0000002TRUE - [1] => - [2] => 4611333 - [3] => /00\7 -) - -Array -( - [0] => array(1,2,3,4)1.0000002TRUE - [1] => - [2] => 4611333 - [3] => /00\7 -) - -Array -( - [0] => array(1,2,3,4)1.0000002TRUE - [1] => - [2] => 4611333 - [3] => /00\7 -) - -*** Testing print_r() on miscellaneous input arguments *** - --- Iteration 1 -- - - - --- Iteration 2 -- - - - --- Iteration 3 -- - - - --- Iteration 4 -- - - -Done diff --git a/ext/standard/tests/general_functions/print_r_64bit.phpt b/ext/standard/tests/general_functions/print_r_64bit.phpt deleted file mode 100644 index 6026b959d7c4c..0000000000000 --- a/ext/standard/tests/general_functions/print_r_64bit.phpt +++ /dev/null @@ -1,1700 +0,0 @@ ---TEST-- -Test print_r() function ---SKIPIF-- - ---INI-- -precision=14 ---FILE-- - 'One'), - array("test" => "is_array"), - array(0), - array(-1), - array(10.5, 5.6), - array("string", "test"), - array('string', 'test'), -); -/* calling check_printr() to display contents of $arrays */ -check_printr($arrays); - -echo "\n*** Testing print_r() on object variables ***\n"; -#[AllowDynamicProperties] -class object_class -{ - var $value; - public $public_var1 = 10; - private $private_var1 = 20; - private $private_var2; - protected $protected_var1 = "string_1"; - protected $protected_var2; - - function __construct ( ) { - $this->value = 50; - $this->public_var2 = 11; - $this->private_var2 = 21; - $this->protected_var2 = "string_2"; - } - - public function foo1() { - echo "foo1() is called\n"; - } - protected function foo2() { - echo "foo2() is called\n"; - } - private function foo3() { - echo "foo3() is called\n"; - } -} -/* class with no member */ -class no_member_class { - // no members -} - -/* class with member as object of other class */ -#[AllowDynamicProperties] -class contains_object_class -{ - var $p = 30; - var $class_object1; - public $class_object2; - private $class_object3; - protected $class_object4; - var $no_member_class_object; - - public function func() { - echo "func() is called \n"; - } - - function __construct () { - $this->class_object1 = new object_class(); - $this->class_object2 = new object_class(); - $this->class_object3 = $this->class_object1; - $this->class_object4 = $this->class_object2; - $this->no_member_class_object = new no_member_class(); - $this->class_object5 = $this; //recursive reference - } -} - -/* objects of different classes */ -$obj = new contains_object_class; -$temp_class_obj = new object_class(); - -/* object which is unset */ -$unset_obj = new object_class(); -unset($unset_obj); - -$objects = array ( - new object_class, - new no_member_class, - new contains_object_class, - $obj, - $obj->class_object1, - $obj->class_object2, - $obj->no_member_class_object, - $temp_class_obj, - @$unset_obj -); -/* calling check_printr() to display contents of the objects using print_r() */ -check_printr($objects); - -echo "\n** Testing print_r() on objects having circular reference **\n"; -$recursion_obj1 = new object_class(); -$recursion_obj2 = new object_class(); -$recursion_obj1->obj = &$recursion_obj2; //circular reference -$recursion_obj2->obj = &$recursion_obj1; //circular reference -print_r($recursion_obj2); - -echo "\n*** Testing print_r() on resources ***\n"; -/* file type resource */ -$file_handle = fopen(__FILE__, "r"); - -/* directory type resource */ -$dir_handle = opendir( __DIR__ ); - -$resources = array ( - $file_handle, - $dir_handle -); -/* calling check_printr() to display the resource content type - using print_r() */ -check_printr($resources); - -echo "\n*** Testing print_r() on different combinations of scalar - and non-scalar variables ***\n"; -/* a variable which is unset */ -$unset_var = 10.5; -unset($unset_var); - -/* unset file type resource */ -unset($file_handle); - -$variations = array ( - array( 123, -1.2345, "a" ), - array( "d", array(1, 3, 5), true, null), - array( new no_member_class, array(), false, 0 ), - array( -0.00, "Where am I?", array(7,8,9), TRUE, 'A', 987654321 ), - array( @$unset_var, 2.E+10, 100-20.9, 000004.599998 ), //unusual data - array( "array(1,2,3,4)1.0000002TRUE", @$file_handle, 111333.00+45e5, '/00\7') -); -/* calling check_printr() to display combinations of scalar and - non-scalar variables using print_r() */ -check_printr($variations); - -echo "\n*** Testing print_r() on miscellaneous input arguments ***\n"; -$misc_values = array ( - @$unset_var, - NULL, // NULL argument - @$undef_variable, //undefined variable - null -); -/* calling check_printr() to display miscellaneous data using print_r() */ -check_printr($misc_values); - -/* closing resource handle used */ -closedir($dir_handle); - -echo "Done\n"; -?> ---EXPECTF-- -*** Testing print_r() on integer variables *** - --- Iteration 1 -- -0 -0 -0 --- Iteration 2 -- -83 -83 -83 --- Iteration 3 -- -123000000 -123000000 -123000000 --- Iteration 4 -- --83 --83 --83 --- Iteration 5 -- --12300000 --12300000 --12300000 --- Iteration 6 -- -Array -( - [0] => 1 - [1] => 2 - [2] => 3 - [3] => 4 - [4] => 5 - [5] => 6 - [6] => 7 - [7] => 8 - [8] => 9 - [9] => 10 -) - -Array -( - [0] => 1 - [1] => 2 - [2] => 3 - [3] => 4 - [4] => 5 - [5] => 6 - [6] => 7 - [7] => 8 - [8] => 9 - [9] => 10 -) - -Array -( - [0] => 1 - [1] => 2 - [2] => 3 - [3] => 4 - [4] => 5 - [5] => 6 - [6] => 7 - [7] => 8 - [8] => 9 - [9] => 10 -) - --- Iteration 7 -- -Array -( - [0] => -1 - [1] => -2 - [2] => -3 - [3] => -4 - [4] => -5 - [5] => -6 - [6] => -7 - [7] => -8 - [8] => -9 - [9] => -10 -) - -Array -( - [0] => -1 - [1] => -2 - [2] => -3 - [3] => -4 - [4] => -5 - [5] => -6 - [6] => -7 - [7] => -8 - [8] => -9 - [9] => -10 -) - -Array -( - [0] => -1 - [1] => -2 - [2] => -3 - [3] => -4 - [4] => -5 - [5] => -6 - [6] => -7 - [7] => -8 - [8] => -9 - [9] => -10 -) - --- Iteration 8 -- -2147483647 -2147483647 -2147483647 --- Iteration 9 -- -2147483648 -2147483648 -2147483648 --- Iteration 10 -- --2147483648 --2147483648 --2147483648 --- Iteration 11 -- --2147483647 --2147483647 --2147483647 --- Iteration 12 -- -2147483647 -2147483647 -2147483647 --- Iteration 13 -- --2147483648 --2147483648 --2147483648 --- Iteration 14 -- -2147483647 -2147483647 -2147483647 --- Iteration 15 -- --2147483648 --2147483648 --2147483648 -*** Testing print_r() on float variables *** - --- Iteration 1 -- --0 --0 --0 --- Iteration 2 -- -0 -0 -0 --- Iteration 3 -- -1.234 -1.234 -1.234 --- Iteration 4 -- --1.234 --1.234 --1.234 --- Iteration 5 -- --2 --2 --2 --- Iteration 6 -- -2 -2 -2 --- Iteration 7 -- --0.5 --0.5 --0.5 --- Iteration 8 -- -0.567 -0.567 -0.567 --- Iteration 9 -- --0.00067 --0.00067 --0.00067 --- Iteration 10 -- --670 --670 --670 --- Iteration 11 -- -670 -670 -670 --- Iteration 12 -- -670 -670 -670 --- Iteration 13 -- --0.00410003 --0.00410003 --0.00410003 --- Iteration 14 -- --4100.03 --4100.03 --4100.03 --- Iteration 15 -- -0.004100003 -0.004100003 -0.004100003 --- Iteration 16 -- -4100.003 -4100.003 -4100.003 --- Iteration 17 -- -100000 -100000 -100000 --- Iteration 18 -- --100000 --100000 --100000 --- Iteration 19 -- -1.0E-5 -1.0E-5 -1.0E-5 --- Iteration 20 -- --1.0E-5 --1.0E-5 --1.0E-5 --- Iteration 21 -- -100000 -100000 -100000 --- Iteration 22 -- --100000 --100000 --100000 --- Iteration 23 -- -100000 -100000 -100000 --- Iteration 24 -- --100000 --100000 --100000 --- Iteration 25 -- -100000 -100000 -100000 --- Iteration 26 -- --100000 --100000 --100000 --- Iteration 27 -- -1.0E-5 -1.0E-5 -1.0E-5 --- Iteration 28 -- --1.0E-5 --1.0E-5 --1.0E-5 --- Iteration 29 -- --2147483649 --2147483649 --2147483649 --- Iteration 30 -- -2147483649 -2147483649 -2147483649 --- Iteration 31 -- -2147483649 -2147483649 -2147483649 --- Iteration 32 -- --2147483649 --2147483649 --2147483649 -*** Testing print_r() on string variables *** - --- Iteration 1 -- - - - --- Iteration 2 -- - - - --- Iteration 3 -- - - - --- Iteration 4 -- - - - --- Iteration 5 -- -0 -0 -0 --- Iteration 6 -- -%0 -%0 -%0 --- Iteration 7 -- -\0 -\0 -\0 --- Iteration 8 -- - - - --- Iteration 9 -- -\t -\t -\t --- Iteration 10 -- -PHP -PHP -PHP --- Iteration 11 -- -PHP -PHP -PHP --- Iteration 12 -- -abcd%0n1234%005678%000efgh\xijkl -abcd%0n1234%005678%000efgh\xijkl -abcd%0n1234%005678%000efgh\xijkl --- Iteration 13 -- -abcd%0efgh%0ijkl%0mnop%00qrst%0uvwx%00yz -abcd%0efgh%0ijkl%0mnop%00qrst%0uvwx%00yz -abcd%0efgh%0ijkl%0mnop%00qrst%0uvwx%00yz --- Iteration 14 -- -1234 -5678 - 9100"abcda -1234 -5678 - 9100"abcda -1234 -5678 - 9100"abcda -*** Testing print_r() on boolean variables *** - --- Iteration 1 -- -1 -1 -1 --- Iteration 2 -- - - - --- Iteration 3 -- -1 -1 -1 --- Iteration 4 -- - - -bool(true) - -bool(true) - -*** Testing print_r() on array variables *** - --- Iteration 1 -- -Array -( -) - -Array -( -) - -Array -( -) - --- Iteration 2 -- -Array -( - [0] => -) - -Array -( - [0] => -) - -Array -( - [0] => -) - --- Iteration 3 -- -Array -( - [0] => -) - -Array -( - [0] => -) - -Array -( - [0] => -) - --- Iteration 4 -- -Array -( - [0] => 1 -) - -Array -( - [0] => 1 -) - -Array -( - [0] => 1 -) - --- Iteration 5 -- -Array -( - [0] => -) - -Array -( - [0] => -) - -Array -( - [0] => -) - --- Iteration 6 -- -Array -( - [0] => -) - -Array -( - [0] => -) - -Array -( - [0] => -) - --- Iteration 7 -- -Array -( - [0] => Array - ( - ) - - [1] => Array - ( - ) - -) - -Array -( - [0] => Array - ( - ) - - [1] => Array - ( - ) - -) - -Array -( - [0] => Array - ( - ) - - [1] => Array - ( - ) - -) - --- Iteration 8 -- -Array -( - [0] => Array - ( - [0] => 1 - [1] => 2 - ) - - [1] => Array - ( - [0] => a - [1] => b - ) - -) - -Array -( - [0] => Array - ( - [0] => 1 - [1] => 2 - ) - - [1] => Array - ( - [0] => a - [1] => b - ) - -) - -Array -( - [0] => Array - ( - [0] => 1 - [1] => 2 - ) - - [1] => Array - ( - [0] => a - [1] => b - ) - -) - --- Iteration 9 -- -Array -( - [1] => One -) - -Array -( - [1] => One -) - -Array -( - [1] => One -) - --- Iteration 10 -- -Array -( - [test] => is_array -) - -Array -( - [test] => is_array -) - -Array -( - [test] => is_array -) - --- Iteration 11 -- -Array -( - [0] => 0 -) - -Array -( - [0] => 0 -) - -Array -( - [0] => 0 -) - --- Iteration 12 -- -Array -( - [0] => -1 -) - -Array -( - [0] => -1 -) - -Array -( - [0] => -1 -) - --- Iteration 13 -- -Array -( - [0] => 10.5 - [1] => 5.6 -) - -Array -( - [0] => 10.5 - [1] => 5.6 -) - -Array -( - [0] => 10.5 - [1] => 5.6 -) - --- Iteration 14 -- -Array -( - [0] => string - [1] => test -) - -Array -( - [0] => string - [1] => test -) - -Array -( - [0] => string - [1] => test -) - --- Iteration 15 -- -Array -( - [0] => string - [1] => test -) - -Array -( - [0] => string - [1] => test -) - -Array -( - [0] => string - [1] => test -) - -*** Testing print_r() on object variables *** - --- Iteration 1 -- -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - --- Iteration 2 -- -no_member_class Object -( -) - -no_member_class Object -( -) - -no_member_class Object -( -) - --- Iteration 3 -- -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - --- Iteration 4 -- -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - -contains_object_class Object -( - [p] => 30 - [class_object1] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object2] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object3:contains_object_class:private] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [class_object4:protected] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - ) - - [no_member_class_object] => no_member_class Object - ( - ) - - [class_object5] => contains_object_class Object - *RECURSION* -) - --- Iteration 5 -- -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - --- Iteration 6 -- -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - --- Iteration 7 -- -no_member_class Object -( -) - -no_member_class Object -( -) - -no_member_class Object -( -) - --- Iteration 8 -- -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 -) - --- Iteration 9 -- - - - -** Testing print_r() on objects having circular reference ** -object_class Object -( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - [obj] => object_class Object - ( - [value] => 50 - [public_var1] => 10 - [private_var1:object_class:private] => 20 - [private_var2:object_class:private] => 21 - [protected_var1:protected] => string_1 - [protected_var2:protected] => string_2 - [public_var2] => 11 - [obj] => object_class Object - *RECURSION* - ) - -) - -*** Testing print_r() on resources *** - --- Iteration 1 -- -Resource id #5 -Resource id #5 -Resource id #5 --- Iteration 2 -- -Resource id #6 -Resource id #6 -Resource id #6 -*** Testing print_r() on different combinations of scalar - and non-scalar variables *** - --- Iteration 1 -- -Array -( - [0] => 123 - [1] => -1.2345 - [2] => a -) - -Array -( - [0] => 123 - [1] => -1.2345 - [2] => a -) - -Array -( - [0] => 123 - [1] => -1.2345 - [2] => a -) - --- Iteration 2 -- -Array -( - [0] => d - [1] => Array - ( - [0] => 1 - [1] => 3 - [2] => 5 - ) - - [2] => 1 - [3] => -) - -Array -( - [0] => d - [1] => Array - ( - [0] => 1 - [1] => 3 - [2] => 5 - ) - - [2] => 1 - [3] => -) - -Array -( - [0] => d - [1] => Array - ( - [0] => 1 - [1] => 3 - [2] => 5 - ) - - [2] => 1 - [3] => -) - --- Iteration 3 -- -Array -( - [0] => no_member_class Object - ( - ) - - [1] => Array - ( - ) - - [2] => - [3] => 0 -) - -Array -( - [0] => no_member_class Object - ( - ) - - [1] => Array - ( - ) - - [2] => - [3] => 0 -) - -Array -( - [0] => no_member_class Object - ( - ) - - [1] => Array - ( - ) - - [2] => - [3] => 0 -) - --- Iteration 4 -- -Array -( - [0] => -0 - [1] => Where am I? - [2] => Array - ( - [0] => 7 - [1] => 8 - [2] => 9 - ) - - [3] => 1 - [4] => A - [5] => 987654321 -) - -Array -( - [0] => -0 - [1] => Where am I? - [2] => Array - ( - [0] => 7 - [1] => 8 - [2] => 9 - ) - - [3] => 1 - [4] => A - [5] => 987654321 -) - -Array -( - [0] => -0 - [1] => Where am I? - [2] => Array - ( - [0] => 7 - [1] => 8 - [2] => 9 - ) - - [3] => 1 - [4] => A - [5] => 987654321 -) - --- Iteration 5 -- -Array -( - [0] => - [1] => 20000000000 - [2] => 79.1 - [3] => 4.599998 -) - -Array -( - [0] => - [1] => 20000000000 - [2] => 79.1 - [3] => 4.599998 -) - -Array -( - [0] => - [1] => 20000000000 - [2] => 79.1 - [3] => 4.599998 -) - --- Iteration 6 -- -Array -( - [0] => array(1,2,3,4)1.0000002TRUE - [1] => - [2] => 4611333 - [3] => /00\7 -) - -Array -( - [0] => array(1,2,3,4)1.0000002TRUE - [1] => - [2] => 4611333 - [3] => /00\7 -) - -Array -( - [0] => array(1,2,3,4)1.0000002TRUE - [1] => - [2] => 4611333 - [3] => /00\7 -) - -*** Testing print_r() on miscellaneous input arguments *** - --- Iteration 1 -- - - - --- Iteration 2 -- - - - --- Iteration 3 -- - - - --- Iteration 4 -- - - -Done diff --git a/ext/standard/tests/general_functions/print_r_array_circular.phpt b/ext/standard/tests/general_functions/print_r_array_circular.phpt new file mode 100644 index 0000000000000..a8ee05d778853 --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_array_circular.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test print_r() function with circular array +--FILE-- + +--EXPECT-- +Array +( + [0] => Array + ( + [0] => Array + *RECURSION* + ) + +) diff --git a/ext/standard/tests/general_functions/print_r_arrays.phpt b/ext/standard/tests/general_functions/print_r_arrays.phpt new file mode 100644 index 0000000000000..edb4aee84291a --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_arrays.phpt @@ -0,0 +1,166 @@ +--TEST-- +Test print_r() function with arrays +--INI-- +precision=14 +--FILE-- + 'One'], + ["test" => "is_array"], + [0], + [-1], + [10.5, 5.6], + ['string', 'test'], +]; + +foreach ($values as $value) { + print_r($value, false); + // $ret_string captures the output + $ret_string = print_r($value, true); + echo "\n$ret_string\n"; +} + +?> +--EXPECT-- +Array +( +) + +Array +( +) + +Array +( + [0] => 1 +) + +Array +( + [0] => 1 +) + +Array +( + [0] => Array + ( + ) + + [1] => Array + ( + ) + +) + +Array +( + [0] => Array + ( + ) + + [1] => Array + ( + ) + +) + +Array +( + [0] => Array + ( + [0] => 1 + [1] => 2 + ) + + [1] => Array + ( + [0] => a + [1] => b + ) + +) + +Array +( + [0] => Array + ( + [0] => 1 + [1] => 2 + ) + + [1] => Array + ( + [0] => a + [1] => b + ) + +) + +Array +( + [1] => One +) + +Array +( + [1] => One +) + +Array +( + [test] => is_array +) + +Array +( + [test] => is_array +) + +Array +( + [0] => 0 +) + +Array +( + [0] => 0 +) + +Array +( + [0] => -1 +) + +Array +( + [0] => -1 +) + +Array +( + [0] => 10.5 + [1] => 5.6 +) + +Array +( + [0] => 10.5 + [1] => 5.6 +) + +Array +( + [0] => string + [1] => test +) + +Array +( + [0] => string + [1] => test +) diff --git a/ext/standard/tests/general_functions/print_r_arrays_whitespace_sensitive.phpt b/ext/standard/tests/general_functions/print_r_arrays_whitespace_sensitive.phpt new file mode 100644 index 0000000000000..87137712064d1 --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_arrays_whitespace_sensitive.phpt @@ -0,0 +1,50 @@ +--TEST-- +Test print_r() function with arrays, output has trailing whitespaces +--WHITESPACE_SENSITIVE-- +--FILE-- + null], + ['false' => false], + ['empty' => ''], +]; + +foreach ($values as $value) { + print_r($value, false); + // $ret_string captures the output + $ret_string = print_r($value, true); + echo "\n$ret_string\n"; +} + +?> +--EXPECT-- +Array +( + [null] => +) + +Array +( + [null] => +) + +Array +( + [false] => +) + +Array +( + [false] => +) + +Array +( + [empty] => +) + +Array +( + [empty] => +) diff --git a/ext/standard/tests/general_functions/print_r_bools.phpt b/ext/standard/tests/general_functions/print_r_bools.phpt new file mode 100644 index 0000000000000..f96060ac36eb0 --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_bools.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test print_r() function with booleans +--FILE-- + true, + 'false' => false, +]; + +foreach ($values as $key => $value) { + echo "$key:\n"; + print_r($value, false); + // $ret_string captures the output + $ret_string = print_r($value, true); + echo "\n$ret_string\n"; +} + +?> +DONE +--EXPECT-- +true: +1 +1 +false: + + +DONE diff --git a/ext/standard/tests/general_functions/print_r_floats.phpt b/ext/standard/tests/general_functions/print_r_floats.phpt new file mode 100644 index 0000000000000..5da055ce2cb7a --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_floats.phpt @@ -0,0 +1,183 @@ +--TEST-- +Test print_r() function with floats +--INI-- +precision=14 +--FILE-- + +--EXPECT-- +-- Iteration 1 -- +-0 +-0 + +-- Iteration 2 -- +0 +0 + +-- Iteration 3 -- +1.234 +1.234 + +-- Iteration 4 -- +-1.234 +-1.234 + +-- Iteration 5 -- +-2 +-2 + +-- Iteration 6 -- +2 +2 + +-- Iteration 7 -- +-0.5 +-0.5 + +-- Iteration 8 -- +0.567 +0.567 + +-- Iteration 9 -- +-0.00067 +-0.00067 + +-- Iteration 10 -- +-670 +-670 + +-- Iteration 11 -- +670 +670 + +-- Iteration 12 -- +670 +670 + +-- Iteration 13 -- +-0.00410003 +-0.00410003 + +-- Iteration 14 -- +-4100.03 +-4100.03 + +-- Iteration 15 -- +0.004100003 +0.004100003 + +-- Iteration 16 -- +4100.003 +4100.003 + +-- Iteration 17 -- +100000 +100000 + +-- Iteration 18 -- +-100000 +-100000 + +-- Iteration 19 -- +1.0E-5 +1.0E-5 + +-- Iteration 20 -- +-1.0E-5 +-1.0E-5 + +-- Iteration 21 -- +100000 +100000 + +-- Iteration 22 -- +-100000 +-100000 + +-- Iteration 23 -- +100000 +100000 + +-- Iteration 24 -- +-100000 +-100000 + +-- Iteration 25 -- +100000 +100000 + +-- Iteration 26 -- +-100000 +-100000 + +-- Iteration 27 -- +1.0E-5 +1.0E-5 + +-- Iteration 28 -- +-1.0E-5 +-1.0E-5 + +-- Iteration 29 -- +-2147483649 +-2147483649 + +-- Iteration 30 -- +2147483649 +2147483649 + +-- Iteration 31 -- +2147483649 +2147483649 + +-- Iteration 32 -- +-2147483649 +-2147483649 diff --git a/ext/standard/tests/general_functions/print_r_ints.phpt b/ext/standard/tests/general_functions/print_r_ints.phpt new file mode 100644 index 0000000000000..ba1eb9d96be24 --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_ints.phpt @@ -0,0 +1,131 @@ +--TEST-- +Test print_r() function with integers +--INI-- +precision=14 +--FILE-- + +--EXPECT-- +-- Iteration 1 -- +0 +0 + +-- Iteration 2 -- +83 +83 + +-- Iteration 3 -- +123000000 +123000000 + +-- Iteration 4 -- +-83 +-83 + +-- Iteration 5 -- +-12300000 +-12300000 + +-- Iteration 6 -- +Array +( + [0] => 1 + [1] => 2 + [2] => 3 + [3] => 4 + [4] => 5 + [5] => 6 + [6] => 7 + [7] => 8 + [8] => 9 + [9] => 10 +) + +Array +( + [0] => 1 + [1] => 2 + [2] => 3 + [3] => 4 + [4] => 5 + [5] => 6 + [6] => 7 + [7] => 8 + [8] => 9 + [9] => 10 +) + + +-- Iteration 7 -- +Array +( + [0] => -1 + [1] => -2 + [2] => -3 + [3] => -4 + [4] => -5 + [5] => -6 + [6] => -7 + [7] => -8 + [8] => -9 + [9] => -10 +) + +Array +( + [0] => -1 + [1] => -2 + [2] => -3 + [3] => -4 + [4] => -5 + [5] => -6 + [6] => -7 + [7] => -8 + [8] => -9 + [9] => -10 +) + + +-- Iteration 8 -- +2147483647 +2147483647 + +-- Iteration 9 -- +2147483648 +2147483648 + +-- Iteration 10 -- +-2147483648 +-2147483648 + +-- Iteration 11 -- +-2147483647 +-2147483647 diff --git a/ext/standard/tests/general_functions/print_r_ints_64bit.phpt b/ext/standard/tests/general_functions/print_r_ints_64bit.phpt new file mode 100644 index 0000000000000..f6f8a56d60782 --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_ints_64bit.phpt @@ -0,0 +1,45 @@ +--TEST-- +Test print_r() function with 64 bit integers +--INI-- +precision=14 +--SKIPIF-- + +--FILE-- + +--EXPECT-- +-- Iteration 1 -- +2147483647 +2147483647 +-- Iteration 2 -- +-2147483648 +-2147483648 +-- Iteration 3 -- +2147483647 +2147483647 +-- Iteration 4 -- +-2147483648 +-2147483648 diff --git a/ext/standard/tests/general_functions/print_r_null.phpt b/ext/standard/tests/general_functions/print_r_null.phpt new file mode 100644 index 0000000000000..14a31b1bd8d8d --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_null.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test print_r() function with null +--FILE-- + +DONE +--EXPECT-- +null: + + +DONE diff --git a/ext/standard/tests/general_functions/print_r_object.phpt b/ext/standard/tests/general_functions/print_r_object.phpt new file mode 100644 index 0000000000000..3fe40bc22cfa0 --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_object.phpt @@ -0,0 +1,228 @@ +--TEST-- +Test print_r() function +--FILE-- +value = 50; + $this->public_var2 = 11; + $this->private_var2 = 21; + $this->protected_var2 = "string_2"; + } + + public function foo1() { + echo "foo1() is called\n"; + } + protected function foo2() { + echo "foo2() is called\n"; + } + private function foo3() { + echo "foo3() is called\n"; + } +} + +class no_member_class {} + +/* class with member as object of other class */ +#[AllowDynamicProperties] +class contains_object_class +{ + var $p = 30; + var $class_object1; + public $class_object2; + private $class_object3; + protected $class_object4; + var $no_member_class_object; + + public function func() { + echo "func() is called \n"; + } + + function __construct() { + $this->class_object1 = new object_class(); + $this->class_object2 = new object_class(); + $this->class_object3 = $this->class_object1; + $this->class_object4 = $this->class_object2; + $this->no_member_class_object = new no_member_class(); + $this->class_object5 = $this; //recursive reference + } +} + +$objects = [ + new object_class, + new no_member_class, + new contains_object_class, +]; +check_printr($objects); + +?> +--EXPECT-- +*** Testing print_r() on object variables *** + +-- Iteration 1 -- +object_class Object +( + [value] => 50 + [public_var1] => 10 + [private_var1:object_class:private] => 20 + [private_var2:object_class:private] => 21 + [protected_var1:protected] => string_1 + [protected_var2:protected] => string_2 + [public_var2] => 11 +) + +object_class Object +( + [value] => 50 + [public_var1] => 10 + [private_var1:object_class:private] => 20 + [private_var2:object_class:private] => 21 + [protected_var1:protected] => string_1 + [protected_var2:protected] => string_2 + [public_var2] => 11 +) + + +-- Iteration 2 -- +no_member_class Object +( +) + +no_member_class Object +( +) + + +-- Iteration 3 -- +contains_object_class Object +( + [p] => 30 + [class_object1] => object_class Object + ( + [value] => 50 + [public_var1] => 10 + [private_var1:object_class:private] => 20 + [private_var2:object_class:private] => 21 + [protected_var1:protected] => string_1 + [protected_var2:protected] => string_2 + [public_var2] => 11 + ) + + [class_object2] => object_class Object + ( + [value] => 50 + [public_var1] => 10 + [private_var1:object_class:private] => 20 + [private_var2:object_class:private] => 21 + [protected_var1:protected] => string_1 + [protected_var2:protected] => string_2 + [public_var2] => 11 + ) + + [class_object3:contains_object_class:private] => object_class Object + ( + [value] => 50 + [public_var1] => 10 + [private_var1:object_class:private] => 20 + [private_var2:object_class:private] => 21 + [protected_var1:protected] => string_1 + [protected_var2:protected] => string_2 + [public_var2] => 11 + ) + + [class_object4:protected] => object_class Object + ( + [value] => 50 + [public_var1] => 10 + [private_var1:object_class:private] => 20 + [private_var2:object_class:private] => 21 + [protected_var1:protected] => string_1 + [protected_var2:protected] => string_2 + [public_var2] => 11 + ) + + [no_member_class_object] => no_member_class Object + ( + ) + + [class_object5] => contains_object_class Object + *RECURSION* +) + +contains_object_class Object +( + [p] => 30 + [class_object1] => object_class Object + ( + [value] => 50 + [public_var1] => 10 + [private_var1:object_class:private] => 20 + [private_var2:object_class:private] => 21 + [protected_var1:protected] => string_1 + [protected_var2:protected] => string_2 + [public_var2] => 11 + ) + + [class_object2] => object_class Object + ( + [value] => 50 + [public_var1] => 10 + [private_var1:object_class:private] => 20 + [private_var2:object_class:private] => 21 + [protected_var1:protected] => string_1 + [protected_var2:protected] => string_2 + [public_var2] => 11 + ) + + [class_object3:contains_object_class:private] => object_class Object + ( + [value] => 50 + [public_var1] => 10 + [private_var1:object_class:private] => 20 + [private_var2:object_class:private] => 21 + [protected_var1:protected] => string_1 + [protected_var2:protected] => string_2 + [public_var2] => 11 + ) + + [class_object4:protected] => object_class Object + ( + [value] => 50 + [public_var1] => 10 + [private_var1:object_class:private] => 20 + [private_var2:object_class:private] => 21 + [protected_var1:protected] => string_1 + [protected_var2:protected] => string_2 + [public_var2] => 11 + ) + + [no_member_class_object] => no_member_class Object + ( + ) + + [class_object5] => contains_object_class Object + *RECURSION* +) diff --git a/ext/standard/tests/general_functions/print_r_object_circular.phpt b/ext/standard/tests/general_functions/print_r_object_circular.phpt new file mode 100644 index 0000000000000..2930f341ae76c --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_object_circular.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test print_r() function function with circular objects +--FILE-- +obj = $recursion_obj2; +$recursion_obj2->obj = $recursion_obj1; +print_r($recursion_obj2); + +?> +--EXPECT-- +Circular Object +( + [obj] => Circular Object + ( + [obj] => Circular Object + *RECURSION* + ) + +) diff --git a/ext/standard/tests/general_functions/print_r_resources.phpt b/ext/standard/tests/general_functions/print_r_resources.phpt new file mode 100644 index 0000000000000..7a8ea357ac40a --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_resources.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test print_r() function with resources +--FILE-- + +--EXPECT-- +Resource id #1 +Resource id #1 +Resource id #3 +Resource id #3 diff --git a/ext/standard/tests/general_functions/print_r_strings.phpt b/ext/standard/tests/general_functions/print_r_strings.phpt new file mode 100644 index 0000000000000..b01737978cd39 --- /dev/null +++ b/ext/standard/tests/general_functions/print_r_strings.phpt @@ -0,0 +1,61 @@ +--TEST-- +Test print_r() function with strings +--WHITESPACE_SENSITIVE-- +--FILE-- + +--EXPECT-- +-- Iteration 1 -- + + +-- Iteration 2 -- + + +-- Iteration 3 -- +0 +0 +-- Iteration 4 -- +\0 +\0 +-- Iteration 5 -- + + +-- Iteration 6 -- +\t +\t +-- Iteration 7 -- +PHP +PHP +-- Iteration 8 -- +1234 +5678 + 9100"abcda +1234 +5678 + 9100"abcda diff --git a/ext/standard/tests/general_functions/print_r_strings_nul_bytes.phpt b/ext/standard/tests/general_functions/print_r_strings_nul_bytes.phpt new file mode 100644 index 0000000000000..626e88e613b10 Binary files /dev/null and b/ext/standard/tests/general_functions/print_r_strings_nul_bytes.phpt differ diff --git a/ext/standard/tests/general_functions/proc_open-mb0.phpt b/ext/standard/tests/general_functions/proc_open-mb0.phpt index 545f087574edb..90ad5533f8240 100644 --- a/ext/standard/tests/general_functions/proc_open-mb0.phpt +++ b/ext/standard/tests/general_functions/proc_open-mb0.phpt @@ -38,6 +38,10 @@ proc_close($p); echo $out; +?> +--CLEAN-- + --EXPECTF-- array(4) { diff --git a/ext/standard/tests/general_functions/proc_open-mb1.phpt b/ext/standard/tests/general_functions/proc_open-mb1.phpt index 057979e604c76..bb220a024804b 100644 --- a/ext/standard/tests/general_functions/proc_open-mb1.phpt +++ b/ext/standard/tests/general_functions/proc_open-mb1.phpt @@ -35,6 +35,10 @@ proc_close($p); echo $out; +?> +--CLEAN-- + --EXPECTF-- array(4) { diff --git a/ext/standard/tests/general_functions/proc_open_array.phpt b/ext/standard/tests/general_functions/proc_open_array.phpt index 964b8391cb615..a76f1111ef268 100644 --- a/ext/standard/tests/general_functions/proc_open_array.phpt +++ b/ext/standard/tests/general_functions/proc_open_array.phpt @@ -76,7 +76,7 @@ proc_close($proc); ?> --EXPECT-- Empty command array: -proc_open(): Argument #1 ($command) must have at least one element +proc_open(): Argument #1 ($command) must not be empty Nul byte in program name: Command array element 1 contains a null byte diff --git a/ext/standard/tests/general_functions/var_dump.phpt b/ext/standard/tests/general_functions/var_dump.phpt deleted file mode 100644 index 0cbd1fce9c66c..0000000000000 --- a/ext/standard/tests/general_functions/var_dump.phpt +++ /dev/null @@ -1,1549 +0,0 @@ ---TEST-- -Test var_dump() function ---SKIPIF-- - ---INI-- -precision=14 ---FILE-- - 'One'), - array("test" => "is_array"), - array(0), - array(-1), - array(10.5, 5.6), - array("string", "test"), - array('string', 'test'), -); -/* calling check_vardump() to display contents of an array - using var_dump() */ -check_vardump($arrays); - -echo "\n*** Testing var_dump() on object variables ***\n"; -#[AllowDynamicProperties] -class object_class -{ - var $value; - public $public_var1 = 10; - private $private_var1 = 20; - private $private_var2; - protected $protected_var1 = "string_1"; - protected $protected_var2; - - function __construct() { - $this->value = 50; - $this->public_var2 = 11; - $this->private_var2 = 21; - $this->protected_var2 = "string_2"; - } - - public function foo1() { - echo "foo1() is called\n"; - } - protected function foo2() { - echo "foo2() is called\n"; - } - private function foo3() { - echo "foo3() is called\n"; - } -} -/* class with no member */ -class no_member_class { - // no members -} - -/* class with member as object of other class */ -#[AllowDynamicProperties] -class contains_object_class -{ - var $p = 30; - var $class_object1; - public $class_object2; - private $class_object3; - protected $class_object4; - var $no_member_class_object; - - public function func() { - echo "func() is called \n"; - } - - function __construct() { - $this->class_object1 = new object_class(); - $this->class_object2 = new object_class(); - $this->class_object3 = $this->class_object1; - $this->class_object4 = $this->class_object2; - $this->no_member_class_object = new no_member_class(); - $this->class_object5 = $this; //recursive reference - } -} - -/* objects of different classes */ -$obj = new contains_object_class; -$temp_class_obj = new object_class(); - -/* object which is unset */ -$unset_obj = new object_class(); -unset($unset_obj); - -$objects = array ( - new object_class, - new no_member_class, - new contains_object_class, - $obj, - $obj->class_object1, - $obj->class_object2, - $obj->no_member_class_object, - $temp_class_obj, - @$unset_obj -); -/* calling check_vardump() to display contents of the objects - using var_dump() */ -check_vardump($objects); - -echo "\n** Testing var_dump() on objects having circular reference **\n"; -$recursion_obj1 = new object_class(); -$recursion_obj2 = new object_class(); -$recursion_obj1->obj = &$recursion_obj2; //circular reference -$recursion_obj2->obj = &$recursion_obj1; //circular reference -var_dump($recursion_obj2); - -echo "\n*** Testing var_dump() on resources ***\n"; -/* file type resource */ -$file_handle = fopen(__FILE__, "r"); - -/* directory type resource */ -$dir_handle = opendir( __DIR__ ); - -$resources = array ( - $file_handle, - $dir_handle -); -/* calling check_vardump() to display the resource content type - using var_dump() */ -check_vardump($resources); - -echo "\n*** Testing var_dump() on different combinations of scalar - and non-scalar variables ***\n"; -/* a variable which is unset */ -$unset_var = 10.5; -unset($unset_var); - -/* unset file type resource */ -unset($file_handle); - -$variations = array ( - array( 123, -1.2345, "a" ), - array( "d", array(1, 3, 5), true, null), - array( new no_member_class, array(), false, 0 ), - array( -0.00, "Where am I?", array(7,8,9), TRUE, 'A', 987654321 ), - array( @$unset_var, 2.E+10, 100-20.9, 000004.599998 ), //unusual data - array( "array(1,2,3,4)1.0000002TRUE", @$file_handle, 111333.00+45e5, '/00\7') -); -/* calling check_vardump() to display combinations of scalar and - non-scalar variables using var_dump() */ -check_vardump($variations); - -echo "\n*** Testing var_dump() on miscellaneous input arguments ***\n"; -$misc_values = array ( - @$unset_var, - NULL, // NULL argument - @$undef_variable, //undefined variable - null -); -/* calling check_vardump() to display miscellaneous data using var_dump() */ -check_vardump($misc_values); - -echo "\n*** Testing var_dump() on multiple arguments ***\n"; -var_dump( $integers, $floats, $strings, $arrays, $booleans, $resources, - $objects, $misc_values, $variations ); - -/* closing resource handle used */ -closedir($dir_handle); - -echo "Done\n"; -?> ---EXPECTF-- -*** Testing var_dump() on integer variables *** --- Iteration 1 -- -int(0) --- Iteration 2 -- -int(83) --- Iteration 3 -- -int(123000000) --- Iteration 4 -- -int(-83) --- Iteration 5 -- -int(-12300000) --- Iteration 6 -- -array(10) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - [3]=> - int(4) - [4]=> - int(5) - [5]=> - int(6) - [6]=> - int(7) - [7]=> - int(8) - [8]=> - int(9) - [9]=> - int(10) -} --- Iteration 7 -- -array(10) { - [0]=> - int(-1) - [1]=> - int(-2) - [2]=> - int(-3) - [3]=> - int(-4) - [4]=> - int(-5) - [5]=> - int(-6) - [6]=> - int(-7) - [7]=> - int(-8) - [8]=> - int(-9) - [9]=> - int(-10) -} --- Iteration 8 -- -int(2147483647) --- Iteration 9 -- -float(2147483648) --- Iteration 10 -- -float(-2147483648) --- Iteration 11 -- -int(-2147483647) --- Iteration 12 -- -int(2147483647) --- Iteration 13 -- -float(-2147483648) --- Iteration 14 -- -int(2147483647) --- Iteration 15 -- -float(-2147483648) - -*** Testing var_dump() on float variables *** --- Iteration 1 -- -float(-0) --- Iteration 2 -- -float(0) --- Iteration 3 -- -float(1.234) --- Iteration 4 -- -float(-1.234) --- Iteration 5 -- -float(-2) --- Iteration 6 -- -float(2) --- Iteration 7 -- -float(-0.5) --- Iteration 8 -- -float(0.567) --- Iteration 9 -- -float(-0.00067) --- Iteration 10 -- -float(-670) --- Iteration 11 -- -float(670) --- Iteration 12 -- -float(670) --- Iteration 13 -- -float(-0.00410003) --- Iteration 14 -- -float(-4100.03) --- Iteration 15 -- -float(0.004100003) --- Iteration 16 -- -float(4100.003) --- Iteration 17 -- -float(100000) --- Iteration 18 -- -float(-100000) --- Iteration 19 -- -float(1.0E-5) --- Iteration 20 -- -float(-1.0E-5) --- Iteration 21 -- -float(100000) --- Iteration 22 -- -float(-100000) --- Iteration 23 -- -float(100000) --- Iteration 24 -- -float(-100000) --- Iteration 25 -- -float(100000) --- Iteration 26 -- -float(-100000) --- Iteration 27 -- -float(1.0E-5) --- Iteration 28 -- -float(-1.0E-5) --- Iteration 29 -- -float(-2147483649) --- Iteration 30 -- -float(2147483649) --- Iteration 31 -- -float(2147483649) --- Iteration 32 -- -float(-2147483649) - -*** Testing var_dump() on string variables *** --- Iteration 1 -- -string(0) "" --- Iteration 2 -- -string(0) "" --- Iteration 3 -- -string(1) " " --- Iteration 4 -- -string(1) " " --- Iteration 5 -- -string(1) "0" --- Iteration 6 -- -string(1) "%0" --- Iteration 7 -- -string(2) "\0" --- Iteration 8 -- -string(1) " " --- Iteration 9 -- -string(2) "\t" --- Iteration 10 -- -string(3) "PHP" --- Iteration 11 -- -string(3) "PHP" --- Iteration 12 -- -string(29) "abcd%0n1234%005678%000efgh\xijkl" --- Iteration 13 -- -string(34) "abcd%0efgh%0ijkl%0mnop%00qrst%0uvwx%00yz" --- Iteration 14 -- -string(22) "1234 -5678 - 9100"abcda" - -*** Testing var_dump() on boolean variables *** --- Iteration 1 -- -bool(true) --- Iteration 2 -- -bool(false) --- Iteration 3 -- -bool(true) --- Iteration 4 -- -bool(false) - -*** Testing var_dump() on array variables *** --- Iteration 1 -- -array(0) { -} --- Iteration 2 -- -array(1) { - [0]=> - NULL -} --- Iteration 3 -- -array(1) { - [0]=> - NULL -} --- Iteration 4 -- -array(1) { - [0]=> - bool(true) -} --- Iteration 5 -- -array(1) { - [0]=> - string(0) "" -} --- Iteration 6 -- -array(1) { - [0]=> - string(0) "" -} --- Iteration 7 -- -array(2) { - [0]=> - array(0) { - } - [1]=> - array(0) { - } -} --- Iteration 8 -- -array(2) { - [0]=> - array(2) { - [0]=> - int(1) - [1]=> - int(2) - } - [1]=> - array(2) { - [0]=> - string(1) "a" - [1]=> - string(1) "b" - } -} --- Iteration 9 -- -array(1) { - [1]=> - string(3) "One" -} --- Iteration 10 -- -array(1) { - ["test"]=> - string(8) "is_array" -} --- Iteration 11 -- -array(1) { - [0]=> - int(0) -} --- Iteration 12 -- -array(1) { - [0]=> - int(-1) -} --- Iteration 13 -- -array(2) { - [0]=> - float(10.5) - [1]=> - float(5.6) -} --- Iteration 14 -- -array(2) { - [0]=> - string(6) "string" - [1]=> - string(4) "test" -} --- Iteration 15 -- -array(2) { - [0]=> - string(6) "string" - [1]=> - string(4) "test" -} - -*** Testing var_dump() on object variables *** --- Iteration 1 -- -object(object_class)#6 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) -} --- Iteration 2 -- -object(no_member_class)#7 (0) { -} --- Iteration 3 -- -object(contains_object_class)#8 (7) { - ["p"]=> - int(30) - ["class_object1"]=> - object(object_class)#9 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object2"]=> - object(object_class)#10 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object3":"contains_object_class":private]=> - object(object_class)#9 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object4":protected]=> - object(object_class)#10 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["no_member_class_object"]=> - object(no_member_class)#11 (0) { - } - ["class_object5"]=> - *RECURSION* -} --- Iteration 4 -- -object(contains_object_class)#1 (7) { - ["p"]=> - int(30) - ["class_object1"]=> - object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object2"]=> - object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object3":"contains_object_class":private]=> - object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object4":protected]=> - object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["no_member_class_object"]=> - object(no_member_class)#4 (0) { - } - ["class_object5"]=> - *RECURSION* -} --- Iteration 5 -- -object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) -} --- Iteration 6 -- -object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) -} --- Iteration 7 -- -object(no_member_class)#4 (0) { -} --- Iteration 8 -- -object(object_class)#5 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) -} --- Iteration 9 -- -NULL - -** Testing var_dump() on objects having circular reference ** -object(object_class)#13 (8) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - ["obj"]=> - &object(object_class)#12 (8) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - ["obj"]=> - *RECURSION* - } -} - -*** Testing var_dump() on resources *** --- Iteration 1 -- -resource(%d) of type (stream) --- Iteration 2 -- -resource(%d) of type (stream) - -*** Testing var_dump() on different combinations of scalar - and non-scalar variables *** --- Iteration 1 -- -array(3) { - [0]=> - int(123) - [1]=> - float(-1.2345) - [2]=> - string(1) "a" -} --- Iteration 2 -- -array(4) { - [0]=> - string(1) "d" - [1]=> - array(3) { - [0]=> - int(1) - [1]=> - int(3) - [2]=> - int(5) - } - [2]=> - bool(true) - [3]=> - NULL -} --- Iteration 3 -- -array(4) { - [0]=> - object(no_member_class)#14 (0) { - } - [1]=> - array(0) { - } - [2]=> - bool(false) - [3]=> - int(0) -} --- Iteration 4 -- -array(6) { - [0]=> - float(-0) - [1]=> - string(11) "Where am I?" - [2]=> - array(3) { - [0]=> - int(7) - [1]=> - int(8) - [2]=> - int(9) - } - [3]=> - bool(true) - [4]=> - string(1) "A" - [5]=> - int(987654321) -} --- Iteration 5 -- -array(4) { - [0]=> - NULL - [1]=> - float(20000000000) - [2]=> - float(79.1) - [3]=> - float(4.599998) -} --- Iteration 6 -- -array(4) { - [0]=> - string(27) "array(1,2,3,4)1.0000002TRUE" - [1]=> - NULL - [2]=> - float(4611333) - [3]=> - string(5) "/00\7" -} - -*** Testing var_dump() on miscellaneous input arguments *** --- Iteration 1 -- -NULL --- Iteration 2 -- -NULL --- Iteration 3 -- -NULL --- Iteration 4 -- -NULL - -*** Testing var_dump() on multiple arguments *** -array(15) { - [0]=> - int(0) - [1]=> - int(83) - [2]=> - int(123000000) - [3]=> - int(-83) - [4]=> - int(-12300000) - [5]=> - array(10) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - [3]=> - int(4) - [4]=> - int(5) - [5]=> - int(6) - [6]=> - int(7) - [7]=> - int(8) - [8]=> - int(9) - [9]=> - int(10) - } - [6]=> - array(10) { - [0]=> - int(-1) - [1]=> - int(-2) - [2]=> - int(-3) - [3]=> - int(-4) - [4]=> - int(-5) - [5]=> - int(-6) - [6]=> - int(-7) - [7]=> - int(-8) - [8]=> - int(-9) - [9]=> - int(-10) - } - [7]=> - int(2147483647) - [8]=> - float(2147483648) - [9]=> - float(-2147483648) - [10]=> - int(-2147483647) - [11]=> - int(2147483647) - [12]=> - float(-2147483648) - [13]=> - int(2147483647) - [14]=> - float(-2147483648) -} -array(32) { - [0]=> - float(-0) - [1]=> - float(0) - [2]=> - float(1.234) - [3]=> - float(-1.234) - [4]=> - float(-2) - [5]=> - float(2) - [6]=> - float(-0.5) - [7]=> - float(0.567) - [8]=> - float(-0.00067) - [9]=> - float(-670) - [10]=> - float(670) - [11]=> - float(670) - [12]=> - float(-0.00410003) - [13]=> - float(-4100.03) - [14]=> - float(0.004100003) - [15]=> - float(4100.003) - [16]=> - float(100000) - [17]=> - float(-100000) - [18]=> - float(1.0E-5) - [19]=> - float(-1.0E-5) - [20]=> - float(100000) - [21]=> - float(-100000) - [22]=> - float(100000) - [23]=> - float(-100000) - [24]=> - float(100000) - [25]=> - float(-100000) - [26]=> - float(1.0E-5) - [27]=> - float(-1.0E-5) - [28]=> - float(-2147483649) - [29]=> - float(2147483649) - [30]=> - float(2147483649) - [31]=> - float(-2147483649) -} -array(14) { - [0]=> - string(0) "" - [1]=> - string(0) "" - [2]=> - string(1) " " - [3]=> - string(1) " " - [4]=> - string(1) "0" - [5]=> - string(1) "%0" - [6]=> - string(2) "\0" - [7]=> - string(1) " " - [8]=> - string(2) "\t" - [9]=> - string(3) "PHP" - [10]=> - string(3) "PHP" - [11]=> - string(29) "abcd%0n1234%005678%000efgh\xijkl" - [12]=> - string(34) "abcd%0efgh%0ijkl%0mnop%00qrst%0uvwx%00yz" - [13]=> - string(22) "1234 -5678 - 9100"abcda" -} -array(15) { - [0]=> - array(0) { - } - [1]=> - array(1) { - [0]=> - NULL - } - [2]=> - array(1) { - [0]=> - NULL - } - [3]=> - array(1) { - [0]=> - bool(true) - } - [4]=> - array(1) { - [0]=> - string(0) "" - } - [5]=> - array(1) { - [0]=> - string(0) "" - } - [6]=> - array(2) { - [0]=> - array(0) { - } - [1]=> - array(0) { - } - } - [7]=> - array(2) { - [0]=> - array(2) { - [0]=> - int(1) - [1]=> - int(2) - } - [1]=> - array(2) { - [0]=> - string(1) "a" - [1]=> - string(1) "b" - } - } - [8]=> - array(1) { - [1]=> - string(3) "One" - } - [9]=> - array(1) { - ["test"]=> - string(8) "is_array" - } - [10]=> - array(1) { - [0]=> - int(0) - } - [11]=> - array(1) { - [0]=> - int(-1) - } - [12]=> - array(2) { - [0]=> - float(10.5) - [1]=> - float(5.6) - } - [13]=> - array(2) { - [0]=> - string(6) "string" - [1]=> - string(4) "test" - } - [14]=> - array(2) { - [0]=> - string(6) "string" - [1]=> - string(4) "test" - } -} -array(4) { - [0]=> - bool(true) - [1]=> - bool(false) - [2]=> - bool(true) - [3]=> - bool(false) -} -array(2) { - [0]=> - resource(%d) of type (stream) - [1]=> - resource(%d) of type (stream) -} -array(9) { - [0]=> - object(object_class)#6 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - [1]=> - object(no_member_class)#7 (0) { - } - [2]=> - object(contains_object_class)#8 (7) { - ["p"]=> - int(30) - ["class_object1"]=> - object(object_class)#9 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object2"]=> - object(object_class)#10 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object3":"contains_object_class":private]=> - object(object_class)#9 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object4":protected]=> - object(object_class)#10 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["no_member_class_object"]=> - object(no_member_class)#11 (0) { - } - ["class_object5"]=> - *RECURSION* - } - [3]=> - object(contains_object_class)#1 (7) { - ["p"]=> - int(30) - ["class_object1"]=> - object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object2"]=> - object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object3":"contains_object_class":private]=> - object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object4":protected]=> - object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["no_member_class_object"]=> - object(no_member_class)#4 (0) { - } - ["class_object5"]=> - *RECURSION* - } - [4]=> - object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - [5]=> - object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - [6]=> - object(no_member_class)#4 (0) { - } - [7]=> - object(object_class)#5 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - [8]=> - NULL -} -array(4) { - [0]=> - NULL - [1]=> - NULL - [2]=> - NULL - [3]=> - NULL -} -array(6) { - [0]=> - array(3) { - [0]=> - int(123) - [1]=> - float(-1.2345) - [2]=> - string(1) "a" - } - [1]=> - array(4) { - [0]=> - string(1) "d" - [1]=> - array(3) { - [0]=> - int(1) - [1]=> - int(3) - [2]=> - int(5) - } - [2]=> - bool(true) - [3]=> - NULL - } - [2]=> - array(4) { - [0]=> - object(no_member_class)#14 (0) { - } - [1]=> - array(0) { - } - [2]=> - bool(false) - [3]=> - int(0) - } - [3]=> - array(6) { - [0]=> - float(-0) - [1]=> - string(11) "Where am I?" - [2]=> - array(3) { - [0]=> - int(7) - [1]=> - int(8) - [2]=> - int(9) - } - [3]=> - bool(true) - [4]=> - string(1) "A" - [5]=> - int(987654321) - } - [4]=> - array(4) { - [0]=> - NULL - [1]=> - float(20000000000) - [2]=> - float(79.1) - [3]=> - float(4.599998) - } - [5]=> - array(4) { - [0]=> - string(27) "array(1,2,3,4)1.0000002TRUE" - [1]=> - NULL - [2]=> - float(4611333) - [3]=> - string(5) "/00\7" - } -} -Done diff --git a/ext/standard/tests/general_functions/var_dump_64bit.phpt b/ext/standard/tests/general_functions/var_dump_64bit.phpt deleted file mode 100644 index cbf9c003bdb92..0000000000000 --- a/ext/standard/tests/general_functions/var_dump_64bit.phpt +++ /dev/null @@ -1,1549 +0,0 @@ ---TEST-- -Test var_dump() function ---SKIPIF-- - ---INI-- -precision=14 ---FILE-- - 'One'), - array("test" => "is_array"), - array(0), - array(-1), - array(10.5, 5.6), - array("string", "test"), - array('string', 'test'), -); -/* calling check_vardump() to display contents of an array - using var_dump() */ -check_vardump($arrays); - -echo "\n*** Testing var_dump() on object variables ***\n"; -#[AllowDynamicProperties] -class object_class -{ - var $value; - public $public_var1 = 10; - private $private_var1 = 20; - private $private_var2; - protected $protected_var1 = "string_1"; - protected $protected_var2; - - function __construct ( ) { - $this->value = 50; - $this->public_var2 = 11; - $this->private_var2 = 21; - $this->protected_var2 = "string_2"; - } - - public function foo1() { - echo "foo1() is called\n"; - } - protected function foo2() { - echo "foo2() is called\n"; - } - private function foo3() { - echo "foo3() is called\n"; - } -} -/* class with no member */ -class no_member_class { - // no members -} - -/* class with member as object of other class */ -#[AllowDynamicProperties] -class contains_object_class -{ - var $p = 30; - var $class_object1; - public $class_object2; - private $class_object3; - protected $class_object4; - var $no_member_class_object; - - public function func() { - echo "func() is called \n"; - } - - function __construct () { - $this->class_object1 = new object_class(); - $this->class_object2 = new object_class(); - $this->class_object3 = $this->class_object1; - $this->class_object4 = $this->class_object2; - $this->no_member_class_object = new no_member_class(); - $this->class_object5 = $this; //recursive reference - } -} - -/* objects of different classes */ -$obj = new contains_object_class; -$temp_class_obj = new object_class(); - -/* object which is unset */ -$unset_obj = new object_class(); -unset($unset_obj); - -$objects = array ( - new object_class, - new no_member_class, - new contains_object_class, - $obj, - $obj->class_object1, - $obj->class_object2, - $obj->no_member_class_object, - $temp_class_obj, - @$unset_obj -); -/* calling check_vardump() to display contents of the objects - using var_dump() */ -check_vardump($objects); - -echo "\n** Testing var_dump() on objects having circular reference **\n"; -$recursion_obj1 = new object_class(); -$recursion_obj2 = new object_class(); -$recursion_obj1->obj = &$recursion_obj2; //circular reference -$recursion_obj2->obj = &$recursion_obj1; //circular reference -var_dump($recursion_obj2); - -echo "\n*** Testing var_dump() on resources ***\n"; -/* file type resource */ -$file_handle = fopen(__FILE__, "r"); - -/* directory type resource */ -$dir_handle = opendir( __DIR__ ); - -$resources = array ( - $file_handle, - $dir_handle -); -/* calling check_vardump() to display the resource content type - using var_dump() */ -check_vardump($resources); - -echo "\n*** Testing var_dump() on different combinations of scalar - and non-scalar variables ***\n"; -/* a variable which is unset */ -$unset_var = 10.5; -unset($unset_var); - -/* unset file type resource */ -unset($file_handle); - -$variations = array ( - array( 123, -1.2345, "a" ), - array( "d", array(1, 3, 5), true, null), - array( new no_member_class, array(), false, 0 ), - array( -0.00, "Where am I?", array(7,8,9), TRUE, 'A', 987654321 ), - array( @$unset_var, 2.E+10, 100-20.9, 000004.599998 ), //unusual data - array( "array(1,2,3,4)1.0000002TRUE", @$file_handle, 111333.00+45e5, '/00\7') -); -/* calling check_vardump() to display combinations of scalar and - non-scalar variables using var_dump() */ -check_vardump($variations); - -echo "\n*** Testing var_dump() on miscellaneous input arguments ***\n"; -$misc_values = array ( - @$unset_var, - NULL, // NULL argument - @$undef_variable, //undefined variable - null -); -/* calling check_vardump() to display miscellaneous data using var_dump() */ -check_vardump($misc_values); - -echo "\n*** Testing var_dump() on multiple arguments ***\n"; -var_dump( $integers, $floats, $strings, $arrays, $booleans, $resources, - $objects, $misc_values, $variations ); - -/* closing resource handle used */ -closedir($dir_handle); - -echo "Done\n"; -?> ---EXPECTF-- -*** Testing var_dump() on integer variables *** --- Iteration 1 -- -int(0) --- Iteration 2 -- -int(83) --- Iteration 3 -- -int(123000000) --- Iteration 4 -- -int(-83) --- Iteration 5 -- -int(-12300000) --- Iteration 6 -- -array(10) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - [3]=> - int(4) - [4]=> - int(5) - [5]=> - int(6) - [6]=> - int(7) - [7]=> - int(8) - [8]=> - int(9) - [9]=> - int(10) -} --- Iteration 7 -- -array(10) { - [0]=> - int(-1) - [1]=> - int(-2) - [2]=> - int(-3) - [3]=> - int(-4) - [4]=> - int(-5) - [5]=> - int(-6) - [6]=> - int(-7) - [7]=> - int(-8) - [8]=> - int(-9) - [9]=> - int(-10) -} --- Iteration 8 -- -int(2147483647) --- Iteration 9 -- -int(2147483648) --- Iteration 10 -- -int(-2147483648) --- Iteration 11 -- -int(-2147483647) --- Iteration 12 -- -int(2147483647) --- Iteration 13 -- -int(-2147483648) --- Iteration 14 -- -int(2147483647) --- Iteration 15 -- -int(-2147483648) - -*** Testing var_dump() on float variables *** --- Iteration 1 -- -float(-0) --- Iteration 2 -- -float(0) --- Iteration 3 -- -float(1.234) --- Iteration 4 -- -float(-1.234) --- Iteration 5 -- -float(-2) --- Iteration 6 -- -float(2) --- Iteration 7 -- -float(-0.5) --- Iteration 8 -- -float(0.567) --- Iteration 9 -- -float(-0.00067) --- Iteration 10 -- -float(-670) --- Iteration 11 -- -float(670) --- Iteration 12 -- -float(670) --- Iteration 13 -- -float(-0.00410003) --- Iteration 14 -- -float(-4100.03) --- Iteration 15 -- -float(0.004100003) --- Iteration 16 -- -float(4100.003) --- Iteration 17 -- -float(100000) --- Iteration 18 -- -float(-100000) --- Iteration 19 -- -float(1.0E-5) --- Iteration 20 -- -float(-1.0E-5) --- Iteration 21 -- -float(100000) --- Iteration 22 -- -float(-100000) --- Iteration 23 -- -float(100000) --- Iteration 24 -- -float(-100000) --- Iteration 25 -- -float(100000) --- Iteration 26 -- -float(-100000) --- Iteration 27 -- -float(1.0E-5) --- Iteration 28 -- -float(-1.0E-5) --- Iteration 29 -- -int(-2147483649) --- Iteration 30 -- -int(2147483649) --- Iteration 31 -- -int(2147483649) --- Iteration 32 -- -int(-2147483649) - -*** Testing var_dump() on string variables *** --- Iteration 1 -- -string(0) "" --- Iteration 2 -- -string(0) "" --- Iteration 3 -- -string(1) " " --- Iteration 4 -- -string(1) " " --- Iteration 5 -- -string(1) "0" --- Iteration 6 -- -string(1) "%0" --- Iteration 7 -- -string(2) "\0" --- Iteration 8 -- -string(1) " " --- Iteration 9 -- -string(2) "\t" --- Iteration 10 -- -string(3) "PHP" --- Iteration 11 -- -string(3) "PHP" --- Iteration 12 -- -string(29) "abcd%0n1234%005678%000efgh\xijkl" --- Iteration 13 -- -string(34) "abcd%0efgh%0ijkl%0mnop%00qrst%0uvwx%00yz" --- Iteration 14 -- -string(22) "1234 -5678 - 9100"abcda" - -*** Testing var_dump() on boolean variables *** --- Iteration 1 -- -bool(true) --- Iteration 2 -- -bool(false) --- Iteration 3 -- -bool(true) --- Iteration 4 -- -bool(false) - -*** Testing var_dump() on array variables *** --- Iteration 1 -- -array(0) { -} --- Iteration 2 -- -array(1) { - [0]=> - NULL -} --- Iteration 3 -- -array(1) { - [0]=> - NULL -} --- Iteration 4 -- -array(1) { - [0]=> - bool(true) -} --- Iteration 5 -- -array(1) { - [0]=> - string(0) "" -} --- Iteration 6 -- -array(1) { - [0]=> - string(0) "" -} --- Iteration 7 -- -array(2) { - [0]=> - array(0) { - } - [1]=> - array(0) { - } -} --- Iteration 8 -- -array(2) { - [0]=> - array(2) { - [0]=> - int(1) - [1]=> - int(2) - } - [1]=> - array(2) { - [0]=> - string(1) "a" - [1]=> - string(1) "b" - } -} --- Iteration 9 -- -array(1) { - [1]=> - string(3) "One" -} --- Iteration 10 -- -array(1) { - ["test"]=> - string(8) "is_array" -} --- Iteration 11 -- -array(1) { - [0]=> - int(0) -} --- Iteration 12 -- -array(1) { - [0]=> - int(-1) -} --- Iteration 13 -- -array(2) { - [0]=> - float(10.5) - [1]=> - float(5.6) -} --- Iteration 14 -- -array(2) { - [0]=> - string(6) "string" - [1]=> - string(4) "test" -} --- Iteration 15 -- -array(2) { - [0]=> - string(6) "string" - [1]=> - string(4) "test" -} - -*** Testing var_dump() on object variables *** --- Iteration 1 -- -object(object_class)#6 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) -} --- Iteration 2 -- -object(no_member_class)#7 (0) { -} --- Iteration 3 -- -object(contains_object_class)#8 (7) { - ["p"]=> - int(30) - ["class_object1"]=> - object(object_class)#9 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object2"]=> - object(object_class)#10 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object3":"contains_object_class":private]=> - object(object_class)#9 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object4":protected]=> - object(object_class)#10 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["no_member_class_object"]=> - object(no_member_class)#11 (0) { - } - ["class_object5"]=> - *RECURSION* -} --- Iteration 4 -- -object(contains_object_class)#1 (7) { - ["p"]=> - int(30) - ["class_object1"]=> - object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object2"]=> - object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object3":"contains_object_class":private]=> - object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object4":protected]=> - object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["no_member_class_object"]=> - object(no_member_class)#4 (0) { - } - ["class_object5"]=> - *RECURSION* -} --- Iteration 5 -- -object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) -} --- Iteration 6 -- -object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) -} --- Iteration 7 -- -object(no_member_class)#4 (0) { -} --- Iteration 8 -- -object(object_class)#5 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) -} --- Iteration 9 -- -NULL - -** Testing var_dump() on objects having circular reference ** -object(object_class)#13 (8) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - ["obj"]=> - &object(object_class)#12 (8) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - ["obj"]=> - *RECURSION* - } -} - -*** Testing var_dump() on resources *** --- Iteration 1 -- -resource(5) of type (stream) --- Iteration 2 -- -resource(6) of type (stream) - -*** Testing var_dump() on different combinations of scalar - and non-scalar variables *** --- Iteration 1 -- -array(3) { - [0]=> - int(123) - [1]=> - float(-1.2345) - [2]=> - string(1) "a" -} --- Iteration 2 -- -array(4) { - [0]=> - string(1) "d" - [1]=> - array(3) { - [0]=> - int(1) - [1]=> - int(3) - [2]=> - int(5) - } - [2]=> - bool(true) - [3]=> - NULL -} --- Iteration 3 -- -array(4) { - [0]=> - object(no_member_class)#14 (0) { - } - [1]=> - array(0) { - } - [2]=> - bool(false) - [3]=> - int(0) -} --- Iteration 4 -- -array(6) { - [0]=> - float(-0) - [1]=> - string(11) "Where am I?" - [2]=> - array(3) { - [0]=> - int(7) - [1]=> - int(8) - [2]=> - int(9) - } - [3]=> - bool(true) - [4]=> - string(1) "A" - [5]=> - int(987654321) -} --- Iteration 5 -- -array(4) { - [0]=> - NULL - [1]=> - float(20000000000) - [2]=> - float(79.1) - [3]=> - float(4.599998) -} --- Iteration 6 -- -array(4) { - [0]=> - string(27) "array(1,2,3,4)1.0000002TRUE" - [1]=> - NULL - [2]=> - float(4611333) - [3]=> - string(5) "/00\7" -} - -*** Testing var_dump() on miscellaneous input arguments *** --- Iteration 1 -- -NULL --- Iteration 2 -- -NULL --- Iteration 3 -- -NULL --- Iteration 4 -- -NULL - -*** Testing var_dump() on multiple arguments *** -array(15) { - [0]=> - int(0) - [1]=> - int(83) - [2]=> - int(123000000) - [3]=> - int(-83) - [4]=> - int(-12300000) - [5]=> - array(10) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - [3]=> - int(4) - [4]=> - int(5) - [5]=> - int(6) - [6]=> - int(7) - [7]=> - int(8) - [8]=> - int(9) - [9]=> - int(10) - } - [6]=> - array(10) { - [0]=> - int(-1) - [1]=> - int(-2) - [2]=> - int(-3) - [3]=> - int(-4) - [4]=> - int(-5) - [5]=> - int(-6) - [6]=> - int(-7) - [7]=> - int(-8) - [8]=> - int(-9) - [9]=> - int(-10) - } - [7]=> - int(2147483647) - [8]=> - int(2147483648) - [9]=> - int(-2147483648) - [10]=> - int(-2147483647) - [11]=> - int(2147483647) - [12]=> - int(-2147483648) - [13]=> - int(2147483647) - [14]=> - int(-2147483648) -} -array(32) { - [0]=> - float(-0) - [1]=> - float(0) - [2]=> - float(1.234) - [3]=> - float(-1.234) - [4]=> - float(-2) - [5]=> - float(2) - [6]=> - float(-0.5) - [7]=> - float(0.567) - [8]=> - float(-0.00067) - [9]=> - float(-670) - [10]=> - float(670) - [11]=> - float(670) - [12]=> - float(-0.00410003) - [13]=> - float(-4100.03) - [14]=> - float(0.004100003) - [15]=> - float(4100.003) - [16]=> - float(100000) - [17]=> - float(-100000) - [18]=> - float(1.0E-5) - [19]=> - float(-1.0E-5) - [20]=> - float(100000) - [21]=> - float(-100000) - [22]=> - float(100000) - [23]=> - float(-100000) - [24]=> - float(100000) - [25]=> - float(-100000) - [26]=> - float(1.0E-5) - [27]=> - float(-1.0E-5) - [28]=> - int(-2147483649) - [29]=> - int(2147483649) - [30]=> - int(2147483649) - [31]=> - int(-2147483649) -} -array(14) { - [0]=> - string(0) "" - [1]=> - string(0) "" - [2]=> - string(1) " " - [3]=> - string(1) " " - [4]=> - string(1) "0" - [5]=> - string(1) "%0" - [6]=> - string(2) "\0" - [7]=> - string(1) " " - [8]=> - string(2) "\t" - [9]=> - string(3) "PHP" - [10]=> - string(3) "PHP" - [11]=> - string(29) "abcd%0n1234%005678%000efgh\xijkl" - [12]=> - string(34) "abcd%0efgh%0ijkl%0mnop%00qrst%0uvwx%00yz" - [13]=> - string(22) "1234 -5678 - 9100"abcda" -} -array(15) { - [0]=> - array(0) { - } - [1]=> - array(1) { - [0]=> - NULL - } - [2]=> - array(1) { - [0]=> - NULL - } - [3]=> - array(1) { - [0]=> - bool(true) - } - [4]=> - array(1) { - [0]=> - string(0) "" - } - [5]=> - array(1) { - [0]=> - string(0) "" - } - [6]=> - array(2) { - [0]=> - array(0) { - } - [1]=> - array(0) { - } - } - [7]=> - array(2) { - [0]=> - array(2) { - [0]=> - int(1) - [1]=> - int(2) - } - [1]=> - array(2) { - [0]=> - string(1) "a" - [1]=> - string(1) "b" - } - } - [8]=> - array(1) { - [1]=> - string(3) "One" - } - [9]=> - array(1) { - ["test"]=> - string(8) "is_array" - } - [10]=> - array(1) { - [0]=> - int(0) - } - [11]=> - array(1) { - [0]=> - int(-1) - } - [12]=> - array(2) { - [0]=> - float(10.5) - [1]=> - float(5.6) - } - [13]=> - array(2) { - [0]=> - string(6) "string" - [1]=> - string(4) "test" - } - [14]=> - array(2) { - [0]=> - string(6) "string" - [1]=> - string(4) "test" - } -} -array(4) { - [0]=> - bool(true) - [1]=> - bool(false) - [2]=> - bool(true) - [3]=> - bool(false) -} -array(2) { - [0]=> - resource(5) of type (stream) - [1]=> - resource(6) of type (stream) -} -array(9) { - [0]=> - object(object_class)#6 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - [1]=> - object(no_member_class)#7 (0) { - } - [2]=> - object(contains_object_class)#8 (7) { - ["p"]=> - int(30) - ["class_object1"]=> - object(object_class)#9 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object2"]=> - object(object_class)#10 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object3":"contains_object_class":private]=> - object(object_class)#9 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object4":protected]=> - object(object_class)#10 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["no_member_class_object"]=> - object(no_member_class)#11 (0) { - } - ["class_object5"]=> - *RECURSION* - } - [3]=> - object(contains_object_class)#1 (7) { - ["p"]=> - int(30) - ["class_object1"]=> - object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object2"]=> - object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object3":"contains_object_class":private]=> - object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["class_object4":protected]=> - object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - ["no_member_class_object"]=> - object(no_member_class)#4 (0) { - } - ["class_object5"]=> - *RECURSION* - } - [4]=> - object(object_class)#2 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - [5]=> - object(object_class)#3 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - [6]=> - object(no_member_class)#4 (0) { - } - [7]=> - object(object_class)#5 (7) { - ["value"]=> - int(50) - ["public_var1"]=> - int(10) - ["private_var1":"object_class":private]=> - int(20) - ["private_var2":"object_class":private]=> - int(21) - ["protected_var1":protected]=> - string(8) "string_1" - ["protected_var2":protected]=> - string(8) "string_2" - ["public_var2"]=> - int(11) - } - [8]=> - NULL -} -array(4) { - [0]=> - NULL - [1]=> - NULL - [2]=> - NULL - [3]=> - NULL -} -array(6) { - [0]=> - array(3) { - [0]=> - int(123) - [1]=> - float(-1.2345) - [2]=> - string(1) "a" - } - [1]=> - array(4) { - [0]=> - string(1) "d" - [1]=> - array(3) { - [0]=> - int(1) - [1]=> - int(3) - [2]=> - int(5) - } - [2]=> - bool(true) - [3]=> - NULL - } - [2]=> - array(4) { - [0]=> - object(no_member_class)#14 (0) { - } - [1]=> - array(0) { - } - [2]=> - bool(false) - [3]=> - int(0) - } - [3]=> - array(6) { - [0]=> - float(-0) - [1]=> - string(11) "Where am I?" - [2]=> - array(3) { - [0]=> - int(7) - [1]=> - int(8) - [2]=> - int(9) - } - [3]=> - bool(true) - [4]=> - string(1) "A" - [5]=> - int(987654321) - } - [4]=> - array(4) { - [0]=> - NULL - [1]=> - float(20000000000) - [2]=> - float(79.1) - [3]=> - float(4.599998) - } - [5]=> - array(4) { - [0]=> - string(27) "array(1,2,3,4)1.0000002TRUE" - [1]=> - NULL - [2]=> - float(4611333) - [3]=> - string(5) "/00\7" - } -} -Done diff --git a/ext/standard/tests/general_functions/var_dump_array_circular.phpt b/ext/standard/tests/general_functions/var_dump_array_circular.phpt new file mode 100644 index 0000000000000..5bee8eb481358 --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_array_circular.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test var_dump() function with circular array +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + &array(1) { + [0]=> + *RECURSION* + } +} diff --git a/ext/standard/tests/general_functions/var_dump_arrays.phpt b/ext/standard/tests/general_functions/var_dump_arrays.phpt new file mode 100644 index 0000000000000..7b75e75e07cca --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_arrays.phpt @@ -0,0 +1,99 @@ +--TEST-- +Test var_dump() function with arrays +--INI-- +precision=14 +--FILE-- + 'One'], + ["test" => "is_array"], + [0], + [-1], + [10.5, 5.6], + ['string', 'test'], +]; + +foreach ($values as $value) { + var_dump($value); +} + +?> +--EXPECT-- +array(0) { +} +array(1) { + [0]=> + NULL +} +array(1) { + [0]=> + bool(false) +} +array(1) { + [0]=> + bool(true) +} +array(1) { + [0]=> + string(0) "" +} +array(2) { + [0]=> + array(0) { + } + [1]=> + array(0) { + } +} +array(2) { + [0]=> + array(2) { + [0]=> + int(1) + [1]=> + int(2) + } + [1]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" + } +} +array(1) { + [1]=> + string(3) "One" +} +array(1) { + ["test"]=> + string(8) "is_array" +} +array(1) { + [0]=> + int(0) +} +array(1) { + [0]=> + int(-1) +} +array(2) { + [0]=> + float(10.5) + [1]=> + float(5.6) +} +array(2) { + [0]=> + string(6) "string" + [1]=> + string(4) "test" +} diff --git a/ext/standard/tests/general_functions/var_dump_bools.phpt b/ext/standard/tests/general_functions/var_dump_bools.phpt new file mode 100644 index 0000000000000..034a8d7a2af48 --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_bools.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test var_dump() function with booleans +--FILE-- + true, + 'false' => false, +]; + +foreach ($values as $key => $value) { + echo "$key:\n"; + var_dump($value); +} + +?> +DONE +--EXPECT-- +true: +bool(true) +false: +bool(false) +DONE diff --git a/ext/standard/tests/general_functions/var_dump_floats.phpt b/ext/standard/tests/general_functions/var_dump_floats.phpt new file mode 100644 index 0000000000000..9ded48b1d3b17 --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_floats.phpt @@ -0,0 +1,76 @@ +--TEST-- +Test var_dump() function with floats +--INI-- +precision=14 +--FILE-- + +--EXPECT-- +-- Iteration 1 -- +float(-0) +-- Iteration 2 -- +float(0) +-- Iteration 3 -- +float(1.234) +-- Iteration 4 -- +float(-1.234) +-- Iteration 5 -- +float(-2) +-- Iteration 6 -- +float(2) +-- Iteration 7 -- +float(-0.5) +-- Iteration 8 -- +float(0.567) +-- Iteration 9 -- +float(-0.00067) +-- Iteration 10 -- +float(670) +-- Iteration 11 -- +float(-0.00410003) +-- Iteration 12 -- +float(0.004100003) +-- Iteration 13 -- +float(100000) +-- Iteration 14 -- +float(-100000) +-- Iteration 15 -- +float(1.0E-5) +-- Iteration 16 -- +float(-1.0E-5) +-- Iteration 17 -- +float(100000) +-- Iteration 18 -- +float(-100000) diff --git a/ext/standard/tests/general_functions/var_dump_ints.phpt b/ext/standard/tests/general_functions/var_dump_ints.phpt new file mode 100644 index 0000000000000..b9146c10b2aa0 --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_ints.phpt @@ -0,0 +1,92 @@ +--TEST-- +Test var_dump() function with integers +--INI-- +precision=14 +--FILE-- + +--EXPECT-- +-- Iteration 1 -- +int(0) +-- Iteration 2 -- +int(83) +-- Iteration 3 -- +int(123000000) +-- Iteration 4 -- +int(-83) +-- Iteration 5 -- +int(-12300000) +-- Iteration 6 -- +array(10) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) + [5]=> + int(6) + [6]=> + int(7) + [7]=> + int(8) + [8]=> + int(9) + [9]=> + int(10) +} +-- Iteration 7 -- +array(10) { + [0]=> + int(-1) + [1]=> + int(-2) + [2]=> + int(-3) + [3]=> + int(-4) + [4]=> + int(-5) + [5]=> + int(-6) + [6]=> + int(-7) + [7]=> + int(-8) + [8]=> + int(-9) + [9]=> + int(-10) +} +-- Iteration 8 -- +int(2147483647) +-- Iteration 9 -- +int(-2147483647) diff --git a/ext/standard/tests/general_functions/var_dump_ints_32bit.phpt b/ext/standard/tests/general_functions/var_dump_ints_32bit.phpt new file mode 100644 index 0000000000000..7cc818cfb22eb --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_ints_32bit.phpt @@ -0,0 +1,33 @@ +--TEST-- +Test var_dump() function with 32 bit integers +--INI-- +precision=14 +--SKIPIF-- + +--FILE-- + +--EXPECT-- +-- Iteration 1 -- +float(2147483648) +-- Iteration 2 -- +float(-2147483648) diff --git a/ext/standard/tests/general_functions/var_dump_ints_64bit.phpt b/ext/standard/tests/general_functions/var_dump_ints_64bit.phpt new file mode 100644 index 0000000000000..cb01803c163bc --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_ints_64bit.phpt @@ -0,0 +1,45 @@ +--TEST-- +Test var_dump() function with 64 bit integers +--INI-- +precision=14 +--SKIPIF-- + +--FILE-- + +--EXPECT-- +-- Iteration 1 -- +int(2147483647) +-- Iteration 2 -- +int(-2147483648) +-- Iteration 3 -- +int(2147483647) +-- Iteration 4 -- +int(-2147483648) +-- Iteration 5 -- +int(2147483648) +-- Iteration 6 -- +int(-2147483648) diff --git a/ext/standard/tests/general_functions/var_dump_null.phpt b/ext/standard/tests/general_functions/var_dump_null.phpt new file mode 100644 index 0000000000000..e98b74eca930b --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_null.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test var_dump() function with null +--FILE-- + +DONE +--EXPECT-- +NULL +DONE diff --git a/ext/standard/tests/general_functions/var_dump_object.phpt b/ext/standard/tests/general_functions/var_dump_object.phpt new file mode 100644 index 0000000000000..467272574de26 --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_object.phpt @@ -0,0 +1,181 @@ +--TEST-- +Test var_dump() function +--FILE-- +value = 50; + $this->public_var2 = 11; + $this->private_var2 = 21; + $this->protected_var2 = "string_2"; + } + + public function foo1() { + echo "foo1() is called\n"; + } + protected function foo2() { + echo "foo2() is called\n"; + } + private function foo3() { + echo "foo3() is called\n"; + } +} + +class no_member_class {} + +/* class with member as object of other class */ +#[AllowDynamicProperties] +class contains_object_class +{ + var $p = 30; + var $class_object1; + public $class_object2; + private $class_object3; + protected $class_object4; + var $no_member_class_object; + + public function func() { + echo "func() is called \n"; + } + + function __construct() { + $this->class_object1 = new object_class(); + $this->class_object2 = new object_class(); + $this->class_object3 = $this->class_object1; + $this->class_object4 = $this->class_object2; + $this->no_member_class_object = new no_member_class(); + $this->class_object5 = $this; //recursive reference + } +} + +$objects = [ + new object_class, + new no_member_class, + new contains_object_class, +]; +check_var_dump($objects); + +?> +--EXPECT-- +*** Testing var_dump() on object variables *** + +-- Iteration 1 -- +object(object_class)#1 (7) { + ["value"]=> + int(50) + ["public_var1"]=> + int(10) + ["private_var1":"object_class":private]=> + int(20) + ["private_var2":"object_class":private]=> + int(21) + ["protected_var1":protected]=> + string(8) "string_1" + ["protected_var2":protected]=> + string(8) "string_2" + ["public_var2"]=> + int(11) +} + +-- Iteration 2 -- +object(no_member_class)#2 (0) { +} + +-- Iteration 3 -- +object(contains_object_class)#3 (7) { + ["p"]=> + int(30) + ["class_object1"]=> + object(object_class)#4 (7) { + ["value"]=> + int(50) + ["public_var1"]=> + int(10) + ["private_var1":"object_class":private]=> + int(20) + ["private_var2":"object_class":private]=> + int(21) + ["protected_var1":protected]=> + string(8) "string_1" + ["protected_var2":protected]=> + string(8) "string_2" + ["public_var2"]=> + int(11) + } + ["class_object2"]=> + object(object_class)#5 (7) { + ["value"]=> + int(50) + ["public_var1"]=> + int(10) + ["private_var1":"object_class":private]=> + int(20) + ["private_var2":"object_class":private]=> + int(21) + ["protected_var1":protected]=> + string(8) "string_1" + ["protected_var2":protected]=> + string(8) "string_2" + ["public_var2"]=> + int(11) + } + ["class_object3":"contains_object_class":private]=> + object(object_class)#4 (7) { + ["value"]=> + int(50) + ["public_var1"]=> + int(10) + ["private_var1":"object_class":private]=> + int(20) + ["private_var2":"object_class":private]=> + int(21) + ["protected_var1":protected]=> + string(8) "string_1" + ["protected_var2":protected]=> + string(8) "string_2" + ["public_var2"]=> + int(11) + } + ["class_object4":protected]=> + object(object_class)#5 (7) { + ["value"]=> + int(50) + ["public_var1"]=> + int(10) + ["private_var1":"object_class":private]=> + int(20) + ["private_var2":"object_class":private]=> + int(21) + ["protected_var1":protected]=> + string(8) "string_1" + ["protected_var2":protected]=> + string(8) "string_2" + ["public_var2"]=> + int(11) + } + ["no_member_class_object"]=> + object(no_member_class)#6 (0) { + } + ["class_object5"]=> + *RECURSION* +} diff --git a/ext/standard/tests/general_functions/var_dump_object_circular.phpt b/ext/standard/tests/general_functions/var_dump_object_circular.phpt new file mode 100644 index 0000000000000..5670346a4bb99 --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_object_circular.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test var_dump() function function with circular objects +--FILE-- +obj = $recursion_obj2; +$recursion_obj2->obj = $recursion_obj1; +var_dump($recursion_obj2); + +?> +--EXPECT-- +object(Circular)#2 (1) { + ["obj"]=> + object(Circular)#1 (1) { + ["obj"]=> + *RECURSION* + } +} diff --git a/ext/standard/tests/general_functions/var_dump_resources.phpt b/ext/standard/tests/general_functions/var_dump_resources.phpt new file mode 100644 index 0000000000000..facdc83d42c8d --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_resources.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test var_dump() function with resources +--FILE-- + +--EXPECT-- +resource(1) of type (stream) +resource(3) of type (stream) diff --git a/ext/standard/tests/general_functions/var_dump_strings.phpt b/ext/standard/tests/general_functions/var_dump_strings.phpt new file mode 100644 index 0000000000000..88436318badac --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_strings.phpt @@ -0,0 +1,48 @@ +--TEST-- +Test var_dump() function with strings +--WHITESPACE_SENSITIVE-- +--FILE-- + +--EXPECT-- +-- Iteration 1 -- +string(0) "" +-- Iteration 2 -- +string(1) " " +-- Iteration 3 -- +string(1) "0" +-- Iteration 4 -- +string(2) "\0" +-- Iteration 5 -- +string(1) " " +-- Iteration 6 -- +string(2) "\t" +-- Iteration 7 -- +string(3) "PHP" +-- Iteration 8 -- +string(22) "1234 +5678 + 9100"abcda" diff --git a/ext/standard/tests/general_functions/var_dump_strings_nul_bytes.phpt b/ext/standard/tests/general_functions/var_dump_strings_nul_bytes.phpt new file mode 100644 index 0000000000000..20f06e11cd1f8 Binary files /dev/null and b/ext/standard/tests/general_functions/var_dump_strings_nul_bytes.phpt differ diff --git a/ext/standard/tests/gh18209.phpt b/ext/standard/tests/gh18209.phpt new file mode 100644 index 0000000000000..6a759639f7dcb --- /dev/null +++ b/ext/standard/tests/gh18209.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-18209: Use-after-free in extract() with EXTR_REFS +--CREDITS-- +Noam Rathaus (nrathaus) +--FILE-- + 42]; +extract($array, EXTR_REFS); +var_dump($b); + +?> +--EXPECT-- +int(42) +int(43) diff --git a/ext/standard/tests/http/bug47021.phpt b/ext/standard/tests/http/bug47021.phpt index 326eceb687a52..168721f4ec1b6 100644 --- a/ext/standard/tests/http/bug47021.phpt +++ b/ext/standard/tests/http/bug47021.phpt @@ -70,23 +70,27 @@ do_test(1, true); echo "\n"; ?> ---EXPECT-- +--EXPECTF-- + Type='text/plain' Hello -Size=5 -World + +Warning: file_get_contents(http://%s:%d): Failed to open stream: HTTP invalid response format (no colon in header line)! in %s + Type='text/plain' Hello -Size=5 -World + +Warning: file_get_contents(http://%s:%d): Failed to open stream: HTTP invalid response format (no colon in header line)! in %s + Type='text/plain' Hello -Size=5 -World + +Warning: file_get_contents(http://%s:%d): Failed to open stream: HTTP invalid response format (no colon in header line)! in %s + Type='text/plain' Hello -Size=5 -World + +Warning: file_get_contents(http://%s:%d): Failed to open stream: HTTP invalid response format (no colon in header line)! in %s diff --git a/ext/standard/tests/http/bug75535.phpt b/ext/standard/tests/http/bug75535.phpt index 27249c3fa18ec..94348d1a027aa 100644 --- a/ext/standard/tests/http/bug75535.phpt +++ b/ext/standard/tests/http/bug75535.phpt @@ -14,27 +14,14 @@ $responses = array( ['pid' => $pid, 'uri' => $uri] = http_server($responses, $output); -var_dump(http_get_last_response_headers()); - var_dump(file_get_contents($uri)); var_dump($http_response_header); -var_dump(http_get_last_response_headers()); http_server_kill($pid); -?> --EXPECT-- -NULL string(0) "" -array(2) { - [0]=> - string(15) "HTTP/1.0 200 Ok" - [1]=> - string(14) "Content-Length" -} -array(2) { +array(1) { [0]=> string(15) "HTTP/1.0 200 Ok" - [1]=> - string(14) "Content-Length" } diff --git a/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt new file mode 100644 index 0000000000000..744cff9cc72f2 --- /dev/null +++ b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt @@ -0,0 +1,58 @@ +--TEST-- +GHSA-52jp-hrpf-2jff: HTTP stream wrapper truncate redirect location to 1024 bytes (success) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + $loc = str_repeat("y", 8000); + fwrite($conn, "HTTP/1.0 301 Ok\r\nContent-Type: text/html;\r\nLocation: $loc\r\n\r\nbody\r\n"); +CODE; + +$clientCode = <<<'CODE' + function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) { + switch($notification_code) { + case STREAM_NOTIFY_MIME_TYPE_IS: + echo "Found the mime-type: ", $message, PHP_EOL; + break; + case STREAM_NOTIFY_REDIRECTED: + echo "Redirected: "; + var_dump($message); + } + } + + $ctx = stream_context_create(); + stream_context_set_params($ctx, array("notification" => "stream_notification_callback")); + var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx))); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +Found the mime-type: text/html; +Redirected: string(8000) "%s" + +Warning: file_get_contents(http://127.0.0.1:%d): Failed to open stream: %s +string(0) "" +array(3) { + [0]=> + string(15) "HTTP/1.0 301 Ok" + [1]=> + string(24) "Content-Type: text/html;" + [2]=> + string(8010) "Location: %s" +} diff --git a/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt new file mode 100644 index 0000000000000..bc71fd4e41167 --- /dev/null +++ b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt @@ -0,0 +1,55 @@ +--TEST-- +GHSA-52jp-hrpf-2jff: HTTP stream wrapper truncate redirect location to 1024 bytes (over limit) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + $loc = str_repeat("y", 9000); + fwrite($conn, "HTTP/1.0 301 Ok\r\nContent-Type: text/html;\r\nLocation: $loc\r\n\r\nbody\r\n"); +CODE; + +$clientCode = <<<'CODE' + function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) { + switch($notification_code) { + case STREAM_NOTIFY_MIME_TYPE_IS: + echo "Found the mime-type: ", $message, PHP_EOL; + break; + case STREAM_NOTIFY_REDIRECTED: + echo "Redirected: "; + var_dump($message); + } + } + + $ctx = stream_context_create(); + stream_context_set_params($ctx, array("notification" => "stream_notification_callback")); + var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx))); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +Found the mime-type: text/html; + +Warning: file_get_contents(http://127.0.0.1:%d): Failed to open stream: HTTP Location header size is over the limit of 8182 bytes in %s +string(0) "" +array(2) { + [0]=> + string(15) "HTTP/1.0 301 Ok" + [1]=> + string(24) "Content-Type: text/html;" +} diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt new file mode 100644 index 0000000000000..c40123560ef1e --- /dev/null +++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt @@ -0,0 +1,65 @@ +--TEST-- +GHSA-hgf5-96fm-v528: Stream HTTP wrapper header check might omit basic auth header (incorrect inside pos) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + $result = fread($conn, 1024); + $encoded_result = base64_encode($result); + + fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n"); + +CODE; + +$clientCode = <<<'CODE' + $opts = [ + "http" => [ + "method" => "GET", + "header" => "Cookie: foo=bar\nauthorization:x\r\n" + ] + ]; + $ctx = stream_context_create($opts); + var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx)))); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +array(7) { + [0]=> + string(14) "GET / HTTP/1.1" + [1]=> + string(33) "Authorization: Basic dXNlcjpwd2Q=" + [2]=> + string(21) "Host: 127.0.0.1:%d" + [3]=> + string(17) "Connection: close" + [4]=> + string(31) "Cookie: foo=bar +authorization:x" + [5]=> + string(0) "" + [6]=> + string(0) "" +} +array(2) { + [0]=> + string(15) "HTTP/1.0 200 Ok" + [1]=> + string(38) "Content-Type: text/html; charset=utf-8" +} diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt new file mode 100644 index 0000000000000..37a47df060a1c --- /dev/null +++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt @@ -0,0 +1,62 @@ +--TEST-- +GHSA-hgf5-96fm-v528: Header parser of http stream wrapper does not handle folded headers (correct start pos) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + $result = fread($conn, 1024); + $encoded_result = base64_encode($result); + + fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n"); + +CODE; + +$clientCode = <<<'CODE' + $opts = [ + "http" => [ + "method" => "GET", + "header" => "Authorization: Bearer x\r\n" + ] + ]; + $ctx = stream_context_create($opts); + var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx)))); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +array(6) { + [0]=> + string(14) "GET / HTTP/1.1" + [1]=> + string(21) "Host: 127.0.0.1:%d" + [2]=> + string(17) "Connection: close" + [3]=> + string(23) "Authorization: Bearer x" + [4]=> + string(0) "" + [5]=> + string(0) "" +} +array(2) { + [0]=> + string(15) "HTTP/1.0 200 Ok" + [1]=> + string(38) "Content-Type: text/html; charset=utf-8" +} diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt new file mode 100644 index 0000000000000..6c84679ff63bd --- /dev/null +++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt @@ -0,0 +1,64 @@ +--TEST-- +GHSA-hgf5-96fm-v528: Header parser of http stream wrapper does not handle folded headers (correct middle pos) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + $result = fread($conn, 1024); + $encoded_result = base64_encode($result); + + fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n"); + +CODE; + +$clientCode = <<<'CODE' + $opts = [ + "http" => [ + "method" => "GET", + "header" => "Cookie: x=y\r\nAuthorization: Bearer x\r\n" + ] + ]; + $ctx = stream_context_create($opts); + var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx)))); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +array(7) { + [0]=> + string(14) "GET / HTTP/1.1" + [1]=> + string(21) "Host: 127.0.0.1:%d" + [2]=> + string(17) "Connection: close" + [3]=> + string(11) "Cookie: x=y" + [4]=> + string(23) "Authorization: Bearer x" + [5]=> + string(0) "" + [6]=> + string(0) "" +} +array(2) { + [0]=> + string(15) "HTTP/1.0 200 Ok" + [1]=> + string(38) "Content-Type: text/html; charset=utf-8" +} diff --git a/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt new file mode 100644 index 0000000000000..bb7945ce62d0e --- /dev/null +++ b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt @@ -0,0 +1,51 @@ +--TEST-- +GHSA-pcmh-g36c-qc44: Header parser of http stream wrapper does not verify header name and colon (colon) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html\r\nWrong-Header\r\nGood-Header: test\r\n\r\nbody\r\n"); +CODE; + +$clientCode = <<<'CODE' + function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) { + switch($notification_code) { + case STREAM_NOTIFY_MIME_TYPE_IS: + echo "Found the mime-type: ", $message, PHP_EOL; + break; + } + } + + $ctx = stream_context_create(); + stream_context_set_params($ctx, array("notification" => "stream_notification_callback")); + var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx)); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +Found the mime-type: text/html + +Warning: file_get_contents(http://127.0.0.1:%d): Failed to open stream: HTTP invalid response format (no colon in header line)! in %s +bool(false) +array(2) { + [0]=> + string(15) "HTTP/1.0 200 Ok" + [1]=> + string(23) "Content-Type: text/html" +} diff --git a/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt new file mode 100644 index 0000000000000..1d0e4fa70a2c9 --- /dev/null +++ b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt @@ -0,0 +1,51 @@ +--TEST-- +GHSA-pcmh-g36c-qc44: Header parser of http stream wrapper does not verify header name and colon (name) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html\r\nWrong-Header : test\r\nGood-Header: test\r\n\r\nbody\r\n"); +CODE; + +$clientCode = <<<'CODE' + function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) { + switch($notification_code) { + case STREAM_NOTIFY_MIME_TYPE_IS: + echo "Found the mime-type: ", $message, PHP_EOL; + break; + } + } + + $ctx = stream_context_create(); + stream_context_set_params($ctx, array("notification" => "stream_notification_callback")); + var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx)); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +Found the mime-type: text/html + +Warning: file_get_contents(http://127.0.0.1:%d): Failed to open stream: HTTP invalid response format (space in header name)! in %s +bool(false) +array(2) { + [0]=> + string(15) "HTTP/1.0 200 Ok" + [1]=> + string(23) "Content-Type: text/html" +} diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt new file mode 100644 index 0000000000000..f935b5a02ca94 --- /dev/null +++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt @@ -0,0 +1,49 @@ +--TEST-- +GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (single) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html;\r\n charset=utf-8\r\n\r\nbody\r\n"); +CODE; + +$clientCode = <<<'CODE' + function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) { + switch($notification_code) { + case STREAM_NOTIFY_MIME_TYPE_IS: + echo "Found the mime-type: ", $message, PHP_EOL; + break; + } + } + + $ctx = stream_context_create(); + stream_context_set_params($ctx, array("notification" => "stream_notification_callback")); + var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx))); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +Found the mime-type: text/html; charset=utf-8 +string(4) "body" +array(2) { + [0]=> + string(15) "HTTP/1.0 200 Ok" + [1]=> + string(38) "Content-Type: text/html; charset=utf-8" +} diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt new file mode 100644 index 0000000000000..078d605b6718f --- /dev/null +++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt @@ -0,0 +1,51 @@ +--TEST-- +GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (multiple) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html;\r\nCustom-Header: somevalue;\r\n param1=value1; \r\n param2=value2\r\n\r\nbody\r\n"); +CODE; + +$clientCode = <<<'CODE' + function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) { + switch($notification_code) { + case STREAM_NOTIFY_MIME_TYPE_IS: + echo "Found the mime-type: ", $message, PHP_EOL; + break; + } + } + + $ctx = stream_context_create(); + stream_context_set_params($ctx, array("notification" => "stream_notification_callback")); + var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx))); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +Found the mime-type: text/html; +string(4) "body" +array(3) { + [0]=> + string(15) "HTTP/1.0 200 Ok" + [1]=> + string(24) "Content-Type: text/html;" + [2]=> + string(54) "Custom-Header: somevalue; param1=value1; param2=value2" +} diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt new file mode 100644 index 0000000000000..ad5ddc879cead --- /dev/null +++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt @@ -0,0 +1,49 @@ +--TEST-- +GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (empty) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html;\r\n \r\n charset=utf-8\r\n\r\nbody\r\n"); +CODE; + +$clientCode = <<<'CODE' + function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) { + switch($notification_code) { + case STREAM_NOTIFY_MIME_TYPE_IS: + echo "Found the mime-type: ", $message, PHP_EOL; + break; + } + } + + $ctx = stream_context_create(); + stream_context_set_params($ctx, array("notification" => "stream_notification_callback")); + var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx))); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +Found the mime-type: text/html; charset=utf-8 +string(4) "body" +array(2) { + [0]=> + string(15) "HTTP/1.0 200 Ok" + [1]=> + string(38) "Content-Type: text/html; charset=utf-8" +} diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt new file mode 100644 index 0000000000000..d0396e819fbd3 --- /dev/null +++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt @@ -0,0 +1,48 @@ +--TEST-- +GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (first line) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + fwrite($conn, "HTTP/1.0 200 Ok\r\n Content-Type: text/html;\r\n \r\n charset=utf-8\r\n\r\nbody\r\n"); +CODE; + +$clientCode = <<<'CODE' + function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) { + switch($notification_code) { + case STREAM_NOTIFY_MIME_TYPE_IS: + echo "Found the mime-type: ", $message, PHP_EOL; + break; + } + } + + $ctx = stream_context_create(); + stream_context_set_params($ctx, array("notification" => "stream_notification_callback")); + var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx)); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- + +Warning: file_get_contents(http://127.0.0.1:%d): Failed to open stream: HTTP invalid response format (folding header at the start)! in %s +bool(false) +array(1) { + [0]=> + string(15) "HTTP/1.0 200 Ok" +} diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt new file mode 100644 index 0000000000000..037d2002cc537 --- /dev/null +++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt @@ -0,0 +1,48 @@ +--TEST-- +GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (CR before header name) +--FILE-- + [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server); + + phpt_notify(message:"server-accepted"); + + fwrite($conn, "HTTP/1.0 200 Ok\r\n\rIgnored: ignored\r\n\r\nbody\r\n"); +CODE; + +$clientCode = <<<'CODE' + function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) { + switch($notification_code) { + case STREAM_NOTIFY_MIME_TYPE_IS: + echo "Found the mime-type: ", $message, PHP_EOL; + break; + } + } + + $ctx = stream_context_create(); + stream_context_set_params($ctx, array("notification" => "stream_notification_callback")); + var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx)); + var_dump($http_response_header); +CODE; + +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- + +Warning: file_get_contents(http://127.0.0.1:%d): Failed to open stream: HTTP invalid header name (cannot start with CR character)! in %s +bool(false) +array(1) { + [0]=> + string(15) "HTTP/1.0 200 Ok" +} diff --git a/ext/standard/tests/http/http_response_header_05.phpt b/ext/standard/tests/http/http_response_header_05.phpt deleted file mode 100644 index d2a7800f42850..0000000000000 --- a/ext/standard/tests/http/http_response_header_05.phpt +++ /dev/null @@ -1,41 +0,0 @@ ---TEST-- -$http_reponse_header (whitespace-only "header") ---SKIPIF-- - ---INI-- -allow_url_fopen=1 ---FILE-- - $pid, 'uri' => $uri] = http_server($responses, $output); - -var_dump(http_get_last_response_headers()); - -$f = file_get_contents($uri); -var_dump($f); -var_dump($http_response_header); -var_dump(http_get_last_response_headers()); - -http_server_kill($pid); - -?> ---EXPECT-- -NULL -string(4) "Body" -array(2) { - [0]=> - string(15) "HTTP/1.0 200 Ok" - [1]=> - string(0) "" -} -array(2) { - [0]=> - string(15) "HTTP/1.0 200 Ok" - [1]=> - string(0) "" -} diff --git a/ext/standard/tests/streams/bug54623.phpt b/ext/standard/tests/streams/bug54623.phpt index 29d4cbcbeb6c8..d7383fcc8f7ec 100644 --- a/ext/standard/tests/streams/bug54623.phpt +++ b/ext/standard/tests/streams/bug54623.phpt @@ -18,4 +18,4 @@ try { --EXPECTF-- int(%d) int(%d) -fwrite(): supplied resource is not a valid stream resource +fwrite(): Argument #1 ($stream) must be an open stream resource diff --git a/ext/standard/tests/streams/stream_get_meta_data_file_error.phpt b/ext/standard/tests/streams/stream_get_meta_data_file_error.phpt index 61b6182e70a2c..55bdd1860a479 100644 --- a/ext/standard/tests/streams/stream_get_meta_data_file_error.phpt +++ b/ext/standard/tests/streams/stream_get_meta_data_file_error.phpt @@ -19,5 +19,5 @@ echo "Done"; *** Testing stream_get_meta_data() : error conditions *** -- Testing stream_get_meta_data() function with closed stream resource -- -stream_get_meta_data(): supplied resource is not a valid stream resource +stream_get_meta_data(): Argument #1 ($stream) must be an open stream resource Done diff --git a/ext/standard/tests/streams/stream_set_timeout_error.phpt b/ext/standard/tests/streams/stream_set_timeout_error.phpt index 58894b7d8c23c..5567cb159914b 100644 --- a/ext/standard/tests/streams/stream_set_timeout_error.phpt +++ b/ext/standard/tests/streams/stream_set_timeout_error.phpt @@ -39,7 +39,7 @@ echo "Done"; *** Testing stream_set_timeout() : error conditions *** -- Testing stream_set_timeout() function with a closed socket -- -stream_set_timeout(): supplied resource is not a valid stream resource +stream_set_timeout(): Argument #1 ($stream) must be an open stream resource -- Testing stream_set_timeout() function with a stream that does not support timeouts -- bool(false) diff --git a/ext/standard/user_filters.c b/ext/standard/user_filters.c index 88facf1e137f2..d91e168ce53a7 100644 --- a/ext/standard/user_filters.c +++ b/ext/standard/user_filters.c @@ -476,16 +476,19 @@ PHP_FUNCTION(stream_get_filters) ZEND_PARSE_PARAMETERS_NONE(); - array_init(return_value); filters_hash = php_get_stream_filters_hash(); if (filters_hash && !HT_IS_PACKED(filters_hash)) { + array_init(return_value); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); ZEND_HASH_MAP_FOREACH_STR_KEY(filters_hash, filter_name) { if (filter_name) { add_next_index_str(return_value, zend_string_copy(filter_name)); } } ZEND_HASH_FOREACH_END(); + } else { + RETURN_EMPTY_ARRAY(); } /* It's okay to return an empty array if no filters are registered */ } diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c index c5efe7a5b242d..138288dd59d4e 100644 --- a/ext/tidy/tidy.c +++ b/ext/tidy/tidy.c @@ -705,6 +705,7 @@ static void tidy_add_node_default_properties(PHPTidyObj *obj) if (tempnode) { array_init(&children); + zend_hash_real_init_packed(Z_ARRVAL(children)); do { tidy_create_node_object(&temp, obj->ptdoc, tempnode); add_next_index_zval(&children, &temp); diff --git a/ext/tokenizer/tokenizer_data.c b/ext/tokenizer/tokenizer_data.c index a046ab50e1498..a1e131032bcfb 100644 --- a/ext/tokenizer/tokenizer_data.c +++ b/ext/tokenizer/tokenizer_data.c @@ -153,6 +153,7 @@ char *get_token_type_name(int token_type) case T_OBJECT_CAST: return "T_OBJECT_CAST"; case T_BOOL_CAST: return "T_BOOL_CAST"; case T_UNSET_CAST: return "T_UNSET_CAST"; + case T_VOID_CAST: return "T_VOID_CAST"; case T_OBJECT_OPERATOR: return "T_OBJECT_OPERATOR"; case T_NULLSAFE_OBJECT_OPERATOR: return "T_NULLSAFE_OBJECT_OPERATOR"; case T_DOUBLE_ARROW: return "T_DOUBLE_ARROW"; diff --git a/ext/tokenizer/tokenizer_data.stub.php b/ext/tokenizer/tokenizer_data.stub.php index 45f3c89f2de3a..c1e1fd254dfaa 100644 --- a/ext/tokenizer/tokenizer_data.stub.php +++ b/ext/tokenizer/tokenizer_data.stub.php @@ -642,6 +642,11 @@ * @cvalue T_UNSET_CAST */ const T_UNSET_CAST = UNKNOWN; +/** + * @var int + * @cvalue T_VOID_CAST + */ +const T_VOID_CAST = UNKNOWN; /** * @var int * @cvalue T_OBJECT_OPERATOR diff --git a/ext/tokenizer/tokenizer_data_arginfo.h b/ext/tokenizer/tokenizer_data_arginfo.h index 61f6ac1ec3659..9c488d19f1890 100644 --- a/ext/tokenizer/tokenizer_data_arginfo.h +++ b/ext/tokenizer/tokenizer_data_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: d917cab61a2b436a16d2227cdb438add45e42d69 */ + * Stub hash: 19d25d22098f46283b517352cbb302db962b50fd */ static void register_tokenizer_data_symbols(int module_number) { @@ -131,6 +131,7 @@ static void register_tokenizer_data_symbols(int module_number) REGISTER_LONG_CONSTANT("T_OBJECT_CAST", T_OBJECT_CAST, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_BOOL_CAST", T_BOOL_CAST, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_UNSET_CAST", T_UNSET_CAST, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("T_VOID_CAST", T_VOID_CAST, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_OBJECT_OPERATOR", T_OBJECT_OPERATOR, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_NULLSAFE_OBJECT_OPERATOR", T_NULLSAFE_OBJECT_OPERATOR, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_DOUBLE_ARROW", T_DOUBLE_ARROW, CONST_PERSISTENT); diff --git a/ext/xml/tests/toffset_bounds.phpt b/ext/xml/tests/toffset_bounds.phpt new file mode 100644 index 0000000000000..5a3fd22f86cd7 --- /dev/null +++ b/ext/xml/tests/toffset_bounds.phpt @@ -0,0 +1,42 @@ +--TEST-- +XML_OPTION_SKIP_TAGSTART bounds +--EXTENSIONS-- +xml +--FILE-- +"; +$parser = xml_parser_create(); +xml_parser_set_option($parser, XML_OPTION_SKIP_TAGSTART, 100); +$res = xml_parse_into_struct($parser,$sample,$vals,$index); +var_dump($vals); +?> +--EXPECT-- +array(3) { + [0]=> + array(3) { + ["tag"]=> + string(0) "" + ["type"]=> + string(4) "open" + ["level"]=> + int(1) + } + [1]=> + array(3) { + ["tag"]=> + string(0) "" + ["type"]=> + string(8) "complete" + ["level"]=> + int(2) + } + [2]=> + array(3) { + ["tag"]=> + string(0) "" + ["type"]=> + string(5) "close" + ["level"]=> + int(1) + } +} diff --git a/ext/xml/xml.c b/ext/xml/xml.c index fb1aa2f74bbf7..bf9f747599730 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -86,7 +86,7 @@ typedef struct { int toffset; int curtag; zend_long ctag_index; - char **ltags; + zend_string **ltags; bool lastwasopen; bool skipwhite; bool isparsing; @@ -116,8 +116,6 @@ ZEND_GET_MODULE(xml) #define XML_MAXLEVEL 255 /* XXX this should be dynamic */ -#define SKIP_TAGSTART(str) ((str) + (parser->toffset > strlen(str) ? strlen(str) : parser->toffset)) - static zend_class_entry *xml_parser_ce; static zend_object_handlers xml_parser_object_handlers; @@ -138,7 +136,7 @@ inline static unsigned short xml_encode_us_ascii(unsigned char); inline static char xml_decode_us_ascii(unsigned short); static void xml_xmlchar_zval(const XML_Char *, int, const XML_Char *, zval *); static int xml_xmlcharlen(const XML_Char *); -static void xml_add_to_info(xml_parser *parser, const char *name); +static void xml_add_to_info(xml_parser *parser, zend_string *name); inline static zend_string *xml_decode_tag(xml_parser *parser, const XML_Char *tag); void xml_startElementHandler(void *, const XML_Char *, const XML_Char **); @@ -311,7 +309,6 @@ static inline xml_parser *xml_parser_from_obj(zend_object *obj) { static zend_object *xml_parser_create_object(zend_class_entry *class_type) { xml_parser *intern = zend_object_alloc(sizeof(xml_parser), class_type); - memset(intern, 0, sizeof(xml_parser) - sizeof(zend_object)); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); @@ -323,8 +320,11 @@ static void xml_parser_free_ltags(xml_parser *parser) { if (parser->ltags) { int inx; - for (inx = 0; ((inx < parser->level) && (inx < XML_MAXLEVEL)); inx++) - efree(parser->ltags[ inx ]); + for (inx = 0; ((inx < parser->level) && (inx < XML_MAXLEVEL)); inx++) { + if (parser->ltags[inx]) { + zend_string_release_ex(parser->ltags[inx], false); + } + } efree(parser->ltags); } } @@ -553,7 +553,7 @@ static int xml_xmlcharlen(const XML_Char *s) /* }}} */ /* {{{ xml_add_to_info() */ -static void xml_add_to_info(xml_parser *parser, const char *name) +static void xml_add_to_info(xml_parser *parser, zend_string *name) { zval *element; @@ -564,11 +564,10 @@ static void xml_add_to_info(xml_parser *parser, const char *name) SEPARATE_ARRAY(Z_REFVAL(parser->info)); zend_array *arr = Z_ARRVAL_P(Z_REFVAL(parser->info)); - size_t name_len = strlen(name); - if ((element = zend_hash_str_find(arr, name, name_len)) == NULL) { + if ((element = zend_hash_find(arr, name)) == NULL) { zval values; array_init(&values); - element = zend_hash_str_update(arr, name, name_len, &values); + element = zend_hash_update(arr, name, &values); } add_next_index_long(element, parser->curtag); @@ -592,6 +591,17 @@ static zend_string *xml_decode_tag(xml_parser *parser, const XML_Char *tag) } /* }}} */ +static zend_string *xml_stripped_tag(zend_string *tag_name, int offset) +{ + if (offset == 0) { + return zend_string_copy(tag_name); + } else if (offset >= ZSTR_LEN(tag_name)) { + return ZSTR_EMPTY_ALLOC(); + } else { + return zend_string_init(ZSTR_VAL(tag_name) + offset, ZSTR_LEN(tag_name) - offset, false); + } +} + static zval *xml_get_separated_data(xml_parser *parser) { if (EXPECTED(Z_TYPE_P(Z_REFVAL(parser->data)) == IS_ARRAY)) { @@ -632,7 +642,7 @@ void xml_startElementHandler(void *userData, const XML_Char *name, const XML_Cha if (ZEND_FCC_INITIALIZED(parser->startElementHandler)) { zval args[3]; ZVAL_COPY(&args[0], &parser->index); - ZVAL_STRING(&args[1], SKIP_TAGSTART(ZSTR_VAL(tag_name))); + ZVAL_STR(&args[1], xml_stripped_tag(tag_name, parser->toffset)); array_init(&args[2]); while (attributes && *attributes) { @@ -651,7 +661,7 @@ void xml_startElementHandler(void *userData, const XML_Char *name, const XML_Cha zend_call_known_fcc(&parser->startElementHandler, /* retval */ NULL, /* param_count */ 3, args, /* named_params */ NULL); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[1]); + zval_ptr_dtor_str(&args[1]); zval_ptr_dtor(&args[2]); } @@ -663,13 +673,15 @@ void xml_startElementHandler(void *userData, const XML_Char *name, const XML_Cha array_init(&tag); array_init(&atr); - xml_add_to_info(parser, ZSTR_VAL(tag_name) + parser->toffset); + zend_string *stripped_tag = xml_stripped_tag(tag_name, parser->toffset); + xml_add_to_info(parser, stripped_tag); - add_assoc_string(&tag, "tag", SKIP_TAGSTART(ZSTR_VAL(tag_name))); /* cast to avoid gcc-warning */ + add_assoc_str(&tag, "tag", stripped_tag); /* transfer lifetime */ add_assoc_string(&tag, "type", "open"); add_assoc_long(&tag, "level", parser->level); - parser->ltags[parser->level-1] = estrdup(ZSTR_VAL(tag_name)); + /* Because toffset may change, we should use the original tag name */ + parser->ltags[parser->level - 1] = zend_string_copy(tag_name); parser->lastwasopen = 1; attributes = (const XML_Char **) attrs; @@ -731,11 +743,11 @@ void xml_endElementHandler(void *userData, const XML_Char *name) if (ZEND_FCC_INITIALIZED(parser->endElementHandler)) { zval args[2]; ZVAL_COPY(&args[0], &parser->index); - ZVAL_STRING(&args[1], SKIP_TAGSTART(ZSTR_VAL(tag_name))); + ZVAL_STR(&args[1], xml_stripped_tag(tag_name, parser->toffset)); zend_call_known_fcc(&parser->endElementHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[1]); + zval_ptr_dtor_str(&args[1]); } if (!Z_ISUNDEF(parser->data) && !EG(exception)) { @@ -747,15 +759,19 @@ void xml_endElementHandler(void *userData, const XML_Char *name) add_assoc_string(zv, "type", "complete"); } } else { - xml_add_to_info(parser, ZSTR_VAL(tag_name) + parser->toffset); + zend_string *stripped_tag = xml_stripped_tag(tag_name, parser->toffset); + + xml_add_to_info(parser, stripped_tag); zval *data = xml_get_separated_data(parser); if (EXPECTED(data)) { array_init(&tag); - add_assoc_string(&tag, "tag", SKIP_TAGSTART(ZSTR_VAL(tag_name))); /* cast to avoid gcc-warning */ + add_assoc_str(&tag, "tag", stripped_tag); /* transfer lifetime */ add_assoc_string(&tag, "type", "close"); add_assoc_long(&tag, "level", parser->level); zend_hash_next_index_insert(Z_ARRVAL_P(data), &tag); + } else { + zend_string_release_ex(stripped_tag, false); } } @@ -765,7 +781,11 @@ void xml_endElementHandler(void *userData, const XML_Char *name) zend_string_release_ex(tag_name, 0); if ((parser->ltags) && (parser->level <= XML_MAXLEVEL)) { - efree(parser->ltags[parser->level-1]); + zend_string **str = &parser->ltags[parser->level - 1]; + if (*str) { + zend_string_release_ex(*str, false); + *str = NULL; + } } parser->level--; @@ -788,7 +808,7 @@ void xml_characterDataHandler(void *userData, const XML_Char *s, int len) zend_call_known_fcc(&parser->characterDataHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[1]); + zval_ptr_dtor_str(&args[1]); } if (Z_ISUNDEF(parser->data) || EG(exception)) { @@ -864,8 +884,9 @@ void xml_characterDataHandler(void *userData, const XML_Char *s, int len) } ZEND_HASH_FOREACH_END(); if (parser->level <= XML_MAXLEVEL && parser->level > 0 && (doprint || (! parser->skipwhite))) { array_init(&tag); - xml_add_to_info(parser,SKIP_TAGSTART(parser->ltags[parser->level-1])); - add_assoc_string(&tag, "tag", SKIP_TAGSTART(parser->ltags[parser->level-1])); + zend_string *stripped_tag = xml_stripped_tag(parser->ltags[parser->level - 1], parser->toffset); + xml_add_to_info(parser, stripped_tag); + add_assoc_str(&tag, "tag", stripped_tag); /* transfer lifetime */ add_assoc_str(&tag, "value", decoded_value); add_assoc_string(&tag, "type", "cdata"); add_assoc_long(&tag, "level", parser->level); @@ -896,8 +917,8 @@ void xml_processingInstructionHandler(void *userData, const XML_Char *target, co zend_call_known_fcc(&parser->processingInstructionHandler, /* retval */ NULL, /* param_count */ 3, args, /* named_params */ NULL); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[2]); + zval_ptr_dtor_str(&args[1]); + zval_ptr_dtor_str(&args[2]); } /* }}} */ @@ -917,7 +938,7 @@ void xml_defaultHandler(void *userData, const XML_Char *s, int len) zend_call_known_fcc(&parser->defaultHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[1]); + zval_ptr_dtor_str(&args[1]); } /* }}} */ @@ -943,11 +964,11 @@ void xml_unparsedEntityDeclHandler(void *userData, zend_call_known_fcc(&parser->unparsedEntityDeclHandler, /* retval */ NULL, /* param_count */ 6, args, /* named_params */ NULL); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[2]); - zval_ptr_dtor(&args[3]); - zval_ptr_dtor(&args[4]); - zval_ptr_dtor(&args[5]); + zval_ptr_dtor_str(&args[1]); + zval_ptr_dtor_str(&args[2]); + zval_ptr_dtor_str(&args[3]); + zval_ptr_dtor_str(&args[4]); + zval_ptr_dtor_str(&args[5]); } /* }}} */ @@ -971,10 +992,10 @@ void xml_notationDeclHandler(void *userData, const XML_Char *notationName, zend_call_known_fcc(&parser->notationDeclHandler, /* retval */ NULL, /* param_count */ 5, args, /* named_params */ NULL); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[2]); - zval_ptr_dtor(&args[3]); - zval_ptr_dtor(&args[4]); + zval_ptr_dtor_str(&args[1]); + zval_ptr_dtor_str(&args[2]); + zval_ptr_dtor_str(&args[3]); + zval_ptr_dtor_str(&args[4]); } /* }}} */ @@ -1000,10 +1021,10 @@ int xml_externalEntityRefHandler(XML_Parser userData, const XML_Char *openEntity zend_call_known_fcc(&parser->externalEntityRefHandler, /* retval */ &retval, /* param_count */ 5, args, /* named_params */ NULL); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[2]); - zval_ptr_dtor(&args[3]); - zval_ptr_dtor(&args[4]); + zval_ptr_dtor_str(&args[1]); + zval_ptr_dtor_str(&args[2]); + zval_ptr_dtor_str(&args[3]); + zval_ptr_dtor_str(&args[4]); /* TODO Better handling from callable return value */ if (!Z_ISUNDEF(retval)) { @@ -1033,8 +1054,8 @@ void xml_startNamespaceDeclHandler(void *userData,const XML_Char *prefix, const zend_call_known_fcc(&parser->startNamespaceDeclHandler, /* retval */ NULL, /* param_count */ 3, args, /* named_params */ NULL); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[2]); + zval_ptr_dtor_str(&args[1]); + zval_ptr_dtor_str(&args[2]); } /* }}} */ @@ -1054,7 +1075,7 @@ void xml_endNamespaceDeclHandler(void *userData, const XML_Char *prefix) zend_call_known_fcc(&parser->endNamespaceDeclHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[1]); + zval_ptr_dtor_str(&args[1]); } /* }}} */ @@ -1444,8 +1465,7 @@ PHP_FUNCTION(xml_parse_into_struct) parser->level = 0; xml_parser_free_ltags(parser); - parser->ltags = safe_emalloc(XML_MAXLEVEL, sizeof(char *), 0); - memset(parser->ltags, 0, XML_MAXLEVEL * sizeof(char *)); + parser->ltags = ecalloc(XML_MAXLEVEL, sizeof(zend_string *)); XML_SetElementHandler(parser->parser, xml_startElementHandler, xml_endElementHandler); XML_SetCharacterDataHandler(parser->parser, xml_characterDataHandler); diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c index 9bc0af63a791e..b4d02c04ab4ac 100644 --- a/ext/xmlreader/php_xmlreader.c +++ b/ext/xmlreader/php_xmlreader.c @@ -117,7 +117,7 @@ static zval *xmlreader_get_property_ptr_ptr(zend_object *object, zend_string *na xmlreader_prop_handler *hnd = zend_hash_find_ptr(&xmlreader_prop_handlers, name); if (hnd == NULL) { retval = zend_std_get_property_ptr_ptr(object, name, type, cache_slot); - } else { + } else if (cache_slot) { cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; } diff --git a/ext/xmlwriter/tests/bug79029.phpt b/ext/xmlwriter/tests/bug79029.phpt index 7b091e80e84e9..22feb4599e7af 100644 --- a/ext/xmlwriter/tests/bug79029.phpt +++ b/ext/xmlwriter/tests/bug79029.phpt @@ -26,7 +26,7 @@ okey @unlink("bug79029_3.txt"); ?> --EXPECTF-- -Warning: fclose(): %d is not a valid stream resource in %sbug79029.php on line %d +Warning: fclose(): cannot close the provided stream, as it must not be manually closed in %sbug79029.php on line %d -Warning: fclose(): %d is not a valid stream resource in %sbug79029.php on line %d +Warning: fclose(): cannot close the provided stream, as it must not be manually closed in %sbug79029.php on line %d okey diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index e3f87ee1e1636..ba18639aead82 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -15,6 +15,7 @@ */ #include "zend_modules.h" +#include "zend_types.h" #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -123,6 +124,20 @@ static ZEND_FUNCTION(zend_test_deprecated_attr) ZEND_PARSE_PARAMETERS_NONE(); } +static ZEND_FUNCTION(zend_test_nodiscard) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + RETURN_LONG(1); +} + +static ZEND_FUNCTION(zend_test_deprecated_nodiscard) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + RETURN_LONG(1); +} + /* Create a string without terminating null byte. Must be terminated with * zend_terminate_string() before destruction, otherwise a warning is issued * in debug builds. */ @@ -182,6 +197,19 @@ static ZEND_FUNCTION(zend_leak_variable) Z_ADDREF_P(zv); } +static ZEND_FUNCTION(zend_delref) +{ + zval *zv; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zv) == FAILURE) { + RETURN_THROWS(); + } + + Z_TRY_DELREF_P(zv); + + RETURN_NULL(); +} + /* Tests Z_PARAM_OBJ_OR_STR */ static ZEND_FUNCTION(zend_string_or_object) { diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 59cb9661e4e43..10272c51cad49 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -218,6 +218,13 @@ function zend_test_deprecated(mixed $arg = null): void {} #[\Deprecated(message: "custom message")] function zend_test_deprecated_attr(): void {} + #[\NoDiscard(message: "custom message")] + function zend_test_nodiscard(): int {} + + #[\Deprecated(message: "custom message")] + #[\NoDiscard(message: "custom message 2")] + function zend_test_deprecated_nodiscard(): int {} + /** @alias zend_test_void_return */ function zend_test_aliased(): void {} @@ -235,6 +242,8 @@ function zend_leak_variable(mixed $variable): void {} function zend_leak_bytes(int $bytes = 3): void {} + function zend_delref(mixed $variable): void {} + function zend_string_or_object(object|string $param): object|string {} function zend_string_or_object_or_null(object|string|null $param): object|string|null {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index c558b58f65169..62b57223dac2a 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 3082e62e96d5f4383c98638513463c676a7c3a69 */ + * Stub hash: bedc3883fbfe2491c95375beb13140e7fcfd83a5 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -22,6 +22,11 @@ ZEND_END_ARG_INFO() #define arginfo_zend_test_deprecated_attr arginfo_zend_test_void_return +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_nodiscard, 0, 0, IS_LONG, 0) +ZEND_END_ARG_INFO() + +#define arginfo_zend_test_deprecated_nodiscard arginfo_zend_test_nodiscard + #define arginfo_zend_test_aliased arginfo_zend_test_void_return #define arginfo_zend_test_deprecated_aliased arginfo_zend_test_void_return @@ -42,6 +47,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_leak_bytes, 0, 0, IS_VOID, ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, bytes, IS_LONG, 0, "3") ZEND_END_ARG_INFO() +#define arginfo_zend_delref arginfo_zend_leak_variable + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_zend_string_or_object, 0, 1, MAY_BE_OBJECT|MAY_BE_STRING) ZEND_ARG_TYPE_MASK(0, param, MAY_BE_OBJECT|MAY_BE_STRING, NULL) ZEND_END_ARG_INFO() @@ -126,8 +133,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_is_string_marked_as_va ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_get_map_ptr_last, 0, 0, IS_LONG, 0) -ZEND_END_ARG_INFO() +#define arginfo_zend_get_map_ptr_last arginfo_zend_test_nodiscard ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_crash, 0, 0, IS_VOID, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 1, "null") @@ -185,7 +191,7 @@ ZEND_END_ARG_INFO() #define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_aliased_func arginfo_zend_test_void_return -#define arginfo_class__ZendTestClass_is_object arginfo_zend_get_map_ptr_last +#define arginfo_class__ZendTestClass_is_object arginfo_zend_test_nodiscard #define arginfo_class__ZendTestClass___toString arginfo_zend_get_current_func_name @@ -260,10 +266,13 @@ static ZEND_FUNCTION(zend_test_void_return); static ZEND_FUNCTION(zend_test_compile_string); static ZEND_FUNCTION(zend_test_deprecated); static ZEND_FUNCTION(zend_test_deprecated_attr); +static ZEND_FUNCTION(zend_test_nodiscard); +static ZEND_FUNCTION(zend_test_deprecated_nodiscard); static ZEND_FUNCTION(zend_create_unterminated_string); static ZEND_FUNCTION(zend_terminate_string); static ZEND_FUNCTION(zend_leak_variable); static ZEND_FUNCTION(zend_leak_bytes); +static ZEND_FUNCTION(zend_delref); static ZEND_FUNCTION(zend_string_or_object); static ZEND_FUNCTION(zend_string_or_object_or_null); static ZEND_FUNCTION(zend_string_or_stdclass); @@ -355,6 +364,16 @@ static const zend_function_entry ext_functions[] = { #else ZEND_RAW_FENTRY("zend_test_deprecated_attr", zif_zend_test_deprecated_attr, arginfo_zend_test_deprecated_attr, ZEND_ACC_DEPRECATED) #endif +#if (PHP_VERSION_ID >= 80400) + ZEND_RAW_FENTRY("zend_test_nodiscard", zif_zend_test_nodiscard, arginfo_zend_test_nodiscard, ZEND_ACC_NODISCARD, NULL, NULL) +#else + ZEND_RAW_FENTRY("zend_test_nodiscard", zif_zend_test_nodiscard, arginfo_zend_test_nodiscard, ZEND_ACC_NODISCARD) +#endif +#if (PHP_VERSION_ID >= 80400) + ZEND_RAW_FENTRY("zend_test_deprecated_nodiscard", zif_zend_test_deprecated_nodiscard, arginfo_zend_test_deprecated_nodiscard, ZEND_ACC_DEPRECATED|ZEND_ACC_NODISCARD, NULL, NULL) +#else + ZEND_RAW_FENTRY("zend_test_deprecated_nodiscard", zif_zend_test_deprecated_nodiscard, arginfo_zend_test_deprecated_nodiscard, ZEND_ACC_DEPRECATED|ZEND_ACC_NODISCARD) +#endif #if (PHP_VERSION_ID >= 80400) ZEND_RAW_FENTRY("zend_test_aliased", zif_zend_test_void_return, arginfo_zend_test_aliased, 0, NULL, NULL) #else @@ -369,6 +388,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_terminate_string, arginfo_zend_terminate_string) ZEND_FE(zend_leak_variable, arginfo_zend_leak_variable) ZEND_FE(zend_leak_bytes, arginfo_zend_leak_bytes) + ZEND_FE(zend_delref, arginfo_zend_delref) ZEND_FE(zend_string_or_object, arginfo_zend_string_or_object) ZEND_FE(zend_string_or_object_or_null, arginfo_zend_string_or_object_or_null) ZEND_FE(zend_string_or_stdclass, arginfo_zend_string_or_stdclass) @@ -560,6 +580,33 @@ static void register_test_symbols(int module_number) ZVAL_COPY_VALUE(&attribute_Deprecated_func_zend_test_deprecated_attr_0->args[0].value, &attribute_Deprecated_func_zend_test_deprecated_attr_0_arg0); attribute_Deprecated_func_zend_test_deprecated_attr_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + zend_string *attribute_name_NoDiscard_func_zend_test_nodiscard_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1); + zend_attribute *attribute_NoDiscard_func_zend_test_nodiscard_0 = zend_add_function_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_nodiscard", sizeof("zend_test_nodiscard") - 1), attribute_name_NoDiscard_func_zend_test_nodiscard_0, 1); + zend_string_release(attribute_name_NoDiscard_func_zend_test_nodiscard_0); + zval attribute_NoDiscard_func_zend_test_nodiscard_0_arg0; + zend_string *attribute_NoDiscard_func_zend_test_nodiscard_0_arg0_str = zend_string_init("custom message", strlen("custom message"), 1); + ZVAL_STR(&attribute_NoDiscard_func_zend_test_nodiscard_0_arg0, attribute_NoDiscard_func_zend_test_nodiscard_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_NoDiscard_func_zend_test_nodiscard_0->args[0].value, &attribute_NoDiscard_func_zend_test_nodiscard_0_arg0); + attribute_NoDiscard_func_zend_test_nodiscard_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_Deprecated_func_zend_test_deprecated_nodiscard_0 = zend_string_init_interned("Deprecated", sizeof("Deprecated") - 1, 1); + zend_attribute *attribute_Deprecated_func_zend_test_deprecated_nodiscard_0 = zend_add_function_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_deprecated_nodiscard", sizeof("zend_test_deprecated_nodiscard") - 1), attribute_name_Deprecated_func_zend_test_deprecated_nodiscard_0, 1); + zend_string_release(attribute_name_Deprecated_func_zend_test_deprecated_nodiscard_0); + zval attribute_Deprecated_func_zend_test_deprecated_nodiscard_0_arg0; + zend_string *attribute_Deprecated_func_zend_test_deprecated_nodiscard_0_arg0_str = zend_string_init("custom message", strlen("custom message"), 1); + ZVAL_STR(&attribute_Deprecated_func_zend_test_deprecated_nodiscard_0_arg0, attribute_Deprecated_func_zend_test_deprecated_nodiscard_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_Deprecated_func_zend_test_deprecated_nodiscard_0->args[0].value, &attribute_Deprecated_func_zend_test_deprecated_nodiscard_0_arg0); + attribute_Deprecated_func_zend_test_deprecated_nodiscard_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_NoDiscard_func_zend_test_deprecated_nodiscard_1 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, 1); + zend_attribute *attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1 = zend_add_function_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_deprecated_nodiscard", sizeof("zend_test_deprecated_nodiscard") - 1), attribute_name_NoDiscard_func_zend_test_deprecated_nodiscard_1, 1); + zend_string_release(attribute_name_NoDiscard_func_zend_test_deprecated_nodiscard_1); + zval attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1_arg0; + zend_string *attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1_arg0_str = zend_string_init("custom message 2", strlen("custom message 2"), 1); + ZVAL_STR(&attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1_arg0, attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1_arg0_str); + ZVAL_COPY_VALUE(&attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1->args[0].value, &attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1_arg0); + attribute_NoDiscard_func_zend_test_deprecated_nodiscard_1->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + zend_string *attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0 = zend_string_init_interned("ZendTestParameterAttribute", sizeof("ZendTestParameterAttribute") - 1, 1); zend_attribute *attribute_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0 = zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_parameter_with_attribute", sizeof("zend_test_parameter_with_attribute") - 1), 0, attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0, 1); zend_string_release(attribute_name_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0); diff --git a/ext/zend_test/tests/opline_dangling.phpt b/ext/zend_test/tests/opline_dangling.phpt index 3b27b544ca34f..e8765c3048bb2 100644 --- a/ext/zend_test/tests/opline_dangling.phpt +++ b/ext/zend_test/tests/opline_dangling.phpt @@ -6,6 +6,12 @@ https://github.com/php/php-src/pull/12758 zend_test --ENV-- USE_ZEND_ALLOC=1 +--SKIPIF-- + --INI-- zend_test.observe_opline_in_zendmm=1 --FILE-- diff --git a/ext/zend_test/tests/opline_dangling_02.phpt b/ext/zend_test/tests/opline_dangling_02.phpt index 585a9c8395b59..8e0ace62db567 100644 --- a/ext/zend_test/tests/opline_dangling_02.phpt +++ b/ext/zend_test/tests/opline_dangling_02.phpt @@ -4,6 +4,12 @@ possible segfault in `ZEND_FUNC_GET_ARGS` zend_test --ENV-- USE_ZEND_ALLOC=1 +--SKIPIF-- + --INI-- zend_test.observe_opline_in_zendmm=1 --FILE-- diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 65a835867f591..187104d2da4ed 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -353,13 +353,13 @@ typedef struct { #endif } zip_options; +/* Expects opts to be zero-initialized. */ static int php_zip_parse_options(HashTable *options, zip_options *opts) /* {{{ */ { zval *option; /* default values */ - memset(opts, 0, sizeof(zip_options)); opts->flags = ZIP_FL_OVERWRITE; opts->comp_method = -1; /* -1 to not change default */ #ifdef HAVE_ENCRYPTION @@ -889,8 +889,6 @@ static zval *php_zip_get_property_ptr_ptr(zend_object *object, zend_string *name zval *retval = NULL; zip_prop_handler *hnd = NULL; - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; - obj = php_zip_fetch_object(object); if (obj->prop_handler != NULL) { @@ -899,6 +897,8 @@ static zval *php_zip_get_property_ptr_ptr(zend_object *object, zend_string *name if (hnd == NULL) { retval = zend_std_get_property_ptr_ptr(object, name, type, cache_slot); + } else if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; } return retval; @@ -1736,7 +1736,7 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /* size_t path_len = 1; zend_long glob_flags = 0; HashTable *options = NULL; - zip_options opts; + zip_options opts = {0}; int found; zend_string *pattern; @@ -1800,6 +1800,9 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /* if (opts.add_path) { if ((opts.add_path_len + file_stripped_len) > MAXPATHLEN) { + if (basename) { + zend_string_release_ex(basename, 0); + } php_error_docref(NULL, E_WARNING, "Entry name too long (max: %d, %zd given)", MAXPATHLEN - 1, (opts.add_path_len + file_stripped_len)); zend_array_destroy(Z_ARR_P(return_value)); diff --git a/ext/zip/tests/addGlob_empty_options.phpt b/ext/zip/tests/addGlob_empty_options.phpt new file mode 100644 index 0000000000000..f4a4126059a7b --- /dev/null +++ b/ext/zip/tests/addGlob_empty_options.phpt @@ -0,0 +1,22 @@ +--TEST-- +addGlob with empty options +--EXTENSIONS-- +zip +--FILE-- +open($file, ZipArchive::CREATE | ZipArchive::OVERWRITE); +$zip->addGlob(__FILE__, 0, []); +var_dump($zip->statIndex(0)['name'] === __FILE__); +$zip->close(); + +?> +--CLEAN-- + +--EXPECT-- +bool(true) diff --git a/ext/zip/tests/addGlob_too_long_add_path_option.phpt b/ext/zip/tests/addGlob_too_long_add_path_option.phpt new file mode 100644 index 0000000000000..9598eeca40a89 --- /dev/null +++ b/ext/zip/tests/addGlob_too_long_add_path_option.phpt @@ -0,0 +1,21 @@ +--TEST-- +addGlob with too long add_path option +--EXTENSIONS-- +zip +--FILE-- +open($file, ZipArchive::CREATE | ZipArchive::OVERWRITE); +$zip->addGlob(__FILE__, 0, ['add_path' => str_repeat('A', PHP_MAXPATHLEN - 2)]); +$zip->close(); + +?> +--CLEAN-- + +--EXPECTF-- +Warning: ZipArchive::addGlob(): Entry name too long (max: %d, %d given) in %s on line %d diff --git a/ext/zlib/tests/gzclose_basic.phpt b/ext/zlib/tests/gzclose_basic.phpt index 69dc7cfd3a606..c1d6edf4d95e1 100644 --- a/ext/zlib/tests/gzclose_basic.phpt +++ b/ext/zlib/tests/gzclose_basic.phpt @@ -34,6 +34,6 @@ try { ?> --EXPECT-- bool(true) -gzread(): supplied resource is not a valid stream resource +gzread(): Argument #1 ($stream) must be an open stream resource bool(true) -gzread(): supplied resource is not a valid stream resource +gzread(): Argument #1 ($stream) must be an open stream resource diff --git a/ext/zlib/tests/gzeof_variation1.phpt b/ext/zlib/tests/gzeof_variation1.phpt index 40e6899d6e583..fb4191fa7940a 100644 --- a/ext/zlib/tests/gzeof_variation1.phpt +++ b/ext/zlib/tests/gzeof_variation1.phpt @@ -24,4 +24,4 @@ unlink($filename); --EXPECT-- bool(false) bool(false) -gzeof(): supplied resource is not a valid stream resource +gzeof(): Argument #1 ($stream) must be an open stream resource diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 0c5486846c12c..f47d879295ced 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -631,6 +631,7 @@ PHP_FUNCTION(gzfile) /* Initialize return array */ array_init(return_value); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); /* Now loop through the file and do the magic quotes thing if needed */ memset(buf, 0, sizeof(buf)); diff --git a/main/debug_gdb_scripts.c b/main/debug_gdb_scripts.c index 092a57c3f7ea7..3806f6aab60dd 100644 --- a/main/debug_gdb_scripts.c +++ b/main/debug_gdb_scripts.c @@ -698,6 +698,8 @@ asm( ".ascii \"\\\"\\\"\\\"\\n\"\n" ".ascii \"\\n\"\n" ".ascii \"import gdb\\n\"\n" + ".ascii \"import gdb.printing\\n\"\n" + ".ascii \"import gdb.types\\n\"\n" ".ascii \"import re\\n\"\n" ".ascii \"import traceback\\n\"\n" ".ascii \"import os\\n\"\n" @@ -780,28 +782,27 @@ asm( ".ascii \" for bit in range(0, type_mask_size):\\n\"\n" ".ascii \" if type_mask & (1 << bit):\\n\"\n" ".ascii \" type_name = ZendTypeBits.zendTypeName(bit)\\n\"\n" - ".ascii \" match type_name:\\n\"\n" - ".ascii \" case None:\\n\"\n" - ".ascii \" parts.append('(1<<%d)' % bit)\\n\"\n" - ".ascii \" case 'list':\\n\"\n" - ".ascii \" list = t['ptr'].cast(gdb.lookup_type('zend_type_list').pointer())\\n\"\n" - ".ascii \" num_types = int(list['num_types'])\\n\"\n" - ".ascii \" types = list['types'].dereference().cast(gdb.lookup_type('zend_type').array(num_types))\\n\"\n" - ".ascii \" for i in range(0, num_types):\\n\"\n" - ".ascii \" str = self.format_type(types[i])\\n\"\n" - ".ascii \" if any((c in set('|&()')) for c in str):\\n\"\n" - ".ascii \" str = '(%s)' % str\\n\"\n" - ".ascii \" parts.append(str)\\n\"\n" - ".ascii \" case 'union' | 'arena':\\n\"\n" - ".ascii \" meta.append(type_name)\\n\"\n" - ".ascii \" case 'intersection':\\n\"\n" - ".ascii \" meta.append(type_name)\\n\"\n" - ".ascii \" separator = '&'\\n\"\n" - ".ascii \" case 'name':\\n\"\n" - ".ascii \" str = t['ptr'].cast(gdb.lookup_type('zend_string').pointer())\\n\"\n" - ".ascii \" parts.append(format_zstr(str))\\n\"\n" - ".ascii \" case _:\\n\"\n" - ".ascii \" parts.append(type_name)\\n\"\n" + ".ascii \" if type_name is None:\\n\"\n" + ".ascii \" parts.append('(1<<%d)' % bit)\\n\"\n" + ".ascii \" elif type_name == 'list':\\n\"\n" + ".ascii \" list_ptr = t['ptr'].cast(gdb.lookup_type('zend_type_list').pointer())\\n\"\n" + ".ascii \" num_types = int(list_ptr['num_types'])\\n\"\n" + ".ascii \" types = list_ptr['types'].dereference().cast(gdb.lookup_type('zend_type').array(num_types))\\n\"\n" + ".ascii \" for i in range(0, num_types):\\n\"\n" + ".ascii \" type_str = self.format_type(types[i])\\n\"\n" + ".ascii \" if any((c in set('|&()')) for c in type_str):\\n\"\n" + ".ascii \" type_str = '(%s)' % type_str\\n\"\n" + ".ascii \" parts.append(type_str)\\n\"\n" + ".ascii \" elif type_name == 'union' or type_name == 'arena':\\n\"\n" + ".ascii \" meta.append(type_name)\\n\"\n" + ".ascii \" elif type_name == 'intersection':\\n\"\n" + ".ascii \" meta.append(type_name)\\n\"\n" + ".ascii \" separator = '&'\\n\"\n" + ".ascii \" elif type_name == 'name':\\n\"\n" + ".ascii \" name_str = t['ptr'].cast(gdb.lookup_type('zend_string').pointer())\\n\"\n" + ".ascii \" parts.append(format_zstr(name_str))\\n\"\n" + ".ascii \" else:\\n\"\n" + ".ascii \" parts.append(type_name)\\n\"\n" ".ascii \"\\n\"\n" ".ascii \" str = separator.join(parts)\\n\"\n" ".ascii \"\\n\"\n" @@ -1071,15 +1072,15 @@ asm( ".ascii \" self.val = val\\n\"\n" ".ascii \"\\n\"\n" ".ascii \" def to_string(self):\\n\"\n" - ".ascii \" match int(self.val['type']):\\n\"\n" - ".ascii \" case ZendFnTypes.ZEND_INTERNAL_FUNCTION:\\n\"\n" - ".ascii \" typestr = 'internal'\\n\"\n" - ".ascii \" case ZendFnTypes.ZEND_USER_FUNCTION:\\n\"\n" - ".ascii \" typestr = 'user'\\n\"\n" - ".ascii \" case ZendFnTypes.ZEND_EVAL_CODE:\\n\"\n" - ".ascii \" typestr = 'eval'\\n\"\n" - ".ascii \" case _:\\n\"\n" - ".ascii \" typestr = '\?\?\?'\\n\"\n" + ".ascii \" val_type = int(self.val['type'])\\n\"\n" + ".ascii \" if val_type == ZendFnTypes.ZEND_INTERNAL_FUNCTION:\\n\"\n" + ".ascii \" typestr = 'internal'\\n\"\n" + ".ascii \" elif val_type == ZendFnTypes.ZEND_USER_FUNCTION:\\n\"\n" + ".ascii \" typestr = 'user'\\n\"\n" + ".ascii \" elif val_type == ZendFnTypes.ZEND_EVAL_CODE:\\n\"\n" + ".ascii \" typestr = 'eval'\\n\"\n" + ".ascii \" else:\\n\"\n" + ".ascii \" typestr = '\?\?\?'\\n\"\n" ".ascii \"\\n\"\n" ".ascii \" if self.val['common']['function_name']:\\n\"\n" ".ascii \" namestr = format_zstr(self.val['common']['function_name'])\\n\"\n" @@ -1499,13 +1500,12 @@ asm( ".ascii \"\\n\"\n" ".ascii \" bits = self._bits\\n\"\n" ".ascii \" type_bits = None\\n\"\n" - ".ascii \" match type_name:\\n\"\n" - ".ascii \" case 'string':\\n\"\n" - ".ascii \" type_bits = self._str_bits\\n\"\n" - ".ascii \" case 'array':\\n\"\n" - ".ascii \" type_bits = self._array_bits\\n\"\n" - ".ascii \" case 'object':\\n\"\n" - ".ascii \" type_bits = self._obj_bits\\n\"\n" + ".ascii \" if type_name == 'string':\\n\"\n" + ".ascii \" type_bits = self._str_bits\\n\"\n" + ".ascii \" elif type_name == 'array':\\n\"\n" + ".ascii \" type_bits = self._array_bits\\n\"\n" + ".ascii \" elif type_name == 'object':\\n\"\n" + ".ascii \" type_bits = self._obj_bits\\n\"\n" ".ascii \"\\n\"\n" ".ascii \" type_flags = flags & self._flags_mask\\n\"\n" ".ascii \" for i in range(0, 31):\\n\"\n" @@ -1528,15 +1528,14 @@ asm( ".ascii \"\\n\"\n" ".ascii \" if (flags & (1<> self._info_shift) & self._gc_color\\n\"\n" - ".ascii \" match gc_color:\\n\"\n" - ".ascii \" case self._gc_black:\\n\"\n" - ".ascii \" names.append('GC_BLACK')\\n\"\n" - ".ascii \" case self._gc_white:\\n\"\n" - ".ascii \" names.append('GC_WHITE')\\n\"\n" - ".ascii \" case self._gc_grey:\\n\"\n" - ".ascii \" names.append('GC_GREY')\\n\"\n" - ".ascii \" case self._gc_purple:\\n\"\n" - ".ascii \" names.append('GC_PURPLE')\\n\"\n" + ".ascii \" if gc_color == self._gc_black:\\n\"\n" + ".ascii \" names.append('GC_BLACK')\\n\"\n" + ".ascii \" elif gc_color == self._gc_white:\\n\"\n" + ".ascii \" names.append('GC_WHITE')\\n\"\n" + ".ascii \" elif gc_color == self._gc_grey:\\n\"\n" + ".ascii \" names.append('GC_GREY')\\n\"\n" + ".ascii \" elif gc_color == self._gc_purple:\\n\"\n" + ".ascii \" names.append('GC_PURPLE')\\n\"\n" ".ascii \"\\n\"\n" ".ascii \" gc_address = (flags >> self._info_shift) & self._gc_address\\n\"\n" ".ascii \" if gc_address != 0:\\n\"\n" @@ -1575,17 +1574,16 @@ asm( ".ascii \" pattern = re.compile(r'#define (GC_[^\\\\s]+)\\\\s+((0x)\?[0-9a-f]+)')\\n\"\n" ".ascii \" matches = pattern.findall(content)\\n\"\n" ".ascii \" for name, bit, _ in matches:\\n\"\n" - ".ascii \" match name:\\n\"\n" - ".ascii \" case 'GC_TYPE_MASK':\\n\"\n" - ".ascii \" self._type_mask = int(bit, 0)\\n\"\n" - ".ascii \" case 'GC_FLAGS_MASK':\\n\"\n" - ".ascii \" self._flags_mask = int(bit, 0)\\n\"\n" - ".ascii \" case 'GC_INFO_MASK':\\n\"\n" - ".ascii \" self._info_mask = int(bit, 0)\\n\"\n" - ".ascii \" case 'GC_INFO_SHIFT':\\n\"\n" - ".ascii \" self._info_shift = int(bit, 0)\\n\"\n" - ".ascii \" case 'GC_FLAGS_SHIFT':\\n\"\n" - ".ascii \" self._flags_shift = int(bit, 0)\\n\"\n" + ".ascii \" if name == 'GC_TYPE_MASK':\\n\"\n" + ".ascii \" self._type_mask = int(bit, 0)\\n\"\n" + ".ascii \" elif name == 'GC_FLAGS_MASK':\\n\"\n" + ".ascii \" self._flags_mask = int(bit, 0)\\n\"\n" + ".ascii \" elif name == 'GC_INFO_MASK':\\n\"\n" + ".ascii \" self._info_mask = int(bit, 0)\\n\"\n" + ".ascii \" elif name == 'GC_INFO_SHIFT':\\n\"\n" + ".ascii \" self._info_shift = int(bit, 0)\\n\"\n" + ".ascii \" elif name == 'GC_FLAGS_SHIFT':\\n\"\n" + ".ascii \" self._flags_shift = int(bit, 0)\\n\"\n" ".ascii \"\\n\"\n" ".ascii \" # IS_STR_INTERNED GC_IMMUTABLE\\n\"\n" ".ascii \" # IS_STR_PERMANENT (1<<8)\\n\"\n" @@ -1596,13 +1594,12 @@ asm( ".ascii \" bit = bits.get(val)\\n\"\n" ".ascii \" if bit == None:\\n\"\n" ".ascii \" continue\\n\"\n" - ".ascii \" match type:\\n\"\n" - ".ascii \" case 'STR':\\n\"\n" - ".ascii \" target = str_bits\\n\"\n" - ".ascii \" case 'ARRAY':\\n\"\n" - ".ascii \" target = array_bits\\n\"\n" - ".ascii \" case 'OBJ':\\n\"\n" - ".ascii \" target = obj_bits\\n\"\n" + ".ascii \" if type == 'STR':\\n\"\n" + ".ascii \" target = str_bits\\n\"\n" + ".ascii \" elif type == 'ARRAY':\\n\"\n" + ".ascii \" target = array_bits\\n\"\n" + ".ascii \" elif type == 'OBJ':\\n\"\n" + ".ascii \" target = obj_bits\\n\"\n" ".ascii \" target[name] = int(bit)\\n\"\n" ".ascii \"\\n\"\n" ".ascii \" # Hard coded because these are not exposed in header files\\n\"\n" diff --git a/main/main.c b/main/main.c index 4075be8b377e3..50894939782a0 100644 --- a/main/main.c +++ b/main/main.c @@ -74,6 +74,7 @@ #include "zend_dtrace.h" #include "zend_observer.h" #include "zend_system_id.h" +#include "zend_smart_string.h" #include "php_content_types.h" #include "php_ticks.h" @@ -99,20 +100,30 @@ PHPAPI size_t core_globals_offset; const char php_build_date[] = __DATE__ " " __TIME__; -PHPAPI const char *php_version(void) +ZEND_ATTRIBUTE_CONST PHPAPI const char *php_version(void) { return PHP_VERSION; } -PHPAPI unsigned int php_version_id(void) +ZEND_ATTRIBUTE_CONST PHPAPI unsigned int php_version_id(void) { return PHP_VERSION_ID; } +ZEND_ATTRIBUTE_CONST PHPAPI const char *php_build_provider(void) +{ +#ifdef PHP_BUILD_PROVIDER + return PHP_BUILD_PROVIDER; +#else + return NULL; +#endif +} + PHPAPI char *php_get_version(sapi_module_struct *sapi_module) { - char *version_info; - spprintf(&version_info, 0, "PHP %s (%s) (built: %s) (%s)\nCopyright (c) The PHP Group\n%s%s", + smart_string version_info = {0}; + smart_string_append_printf(&version_info, + "PHP %s (%s) (built: %s) (%s)\n", PHP_VERSION, sapi_module->name, php_build_date, #ifdef ZTS "ZTS" @@ -131,16 +142,15 @@ PHPAPI char *php_get_version(sapi_module_struct *sapi_module) #ifdef HAVE_GCOV " GCOV" #endif - , -#ifdef PHP_BUILD_PROVIDER - "Built by " PHP_BUILD_PROVIDER "\n" -#else - "" -#endif - , - get_zend_version() ); - return version_info; + smart_string_appends(&version_info, "Copyright (c) The PHP Group\n"); + if (php_build_provider()) { + smart_string_append_printf(&version_info, "Built by %s\n", php_build_provider()); + } + smart_string_appends(&version_info, get_zend_version()); + smart_string_0(&version_info); + + return version_info.c; } PHPAPI void php_print_version(sapi_module_struct *sapi_module) @@ -1904,8 +1914,6 @@ void php_request_shutdown(void *dummy) */ EG(current_execute_data) = NULL; - php_deactivate_ticks(); - /* 0. Call any open observer end handlers that are still open after a zend_bailout */ if (ZEND_OBSERVER_ENABLED) { zend_observer_fcall_end_all(); @@ -1926,6 +1934,8 @@ void php_request_shutdown(void *dummy) php_output_end_all(); } zend_end_try(); + php_deactivate_ticks(); + /* 4. Reset max_execution_time (no longer executing php code after response sent) */ zend_try { zend_unset_timeout(); diff --git a/main/php_main.h b/main/php_main.h index 889fcf48501f0..a5b049487db23 100644 --- a/main/php_main.h +++ b/main/php_main.h @@ -28,13 +28,20 @@ BEGIN_EXTERN_C() * extensions which want to know the version of PHP at run-time, rather than * the version they were built with at compile-time. */ -PHPAPI const char *php_version(void); +ZEND_ATTRIBUTE_CONST PHPAPI const char *php_version(void); /* Returns the PHP version id the engine was built with. This is useful for * extensions which want to know the version of PHP at run-time, rather than * the version they were built with at compile-time. */ -PHPAPI unsigned int php_version_id(void); +ZEND_ATTRIBUTE_CONST PHPAPI unsigned int php_version_id(void); + +/* Returns the build provider specified at build time. NULL is returned if + * no build provider was specified. This is useful for extensions which want + * to know the origin of a PHP binary at run-time, for example to provide + * statistics. + */ +ZEND_ATTRIBUTE_CONST PHPAPI const char *php_build_provider(void); /* Prints the PHP version string for the -v option. It's in main/ so that * it can be shared between SAPIs. diff --git a/main/php_scandir.c b/main/php_scandir.c index 7d1eb36023665..7bf91bdf7f33d 100644 --- a/main/php_scandir.c +++ b/main/php_scandir.c @@ -83,7 +83,7 @@ PHPAPI int php_scandir(const char *dirname, struct dirent **namelist[], int (*se newv = (struct dirent **) realloc (vector, vector_size * sizeof (struct dirent *)); if (!newv) { - return -1; + goto fail; } vector = newv; } @@ -113,6 +113,7 @@ PHPAPI int php_scandir(const char *dirname, struct dirent **namelist[], int (*se free(vector[nfiles]); } free(vector); + closedir(dirp); return -1; } #endif diff --git a/main/php_streams.h b/main/php_streams.h index 80cb96951ee14..02281c3913fcd 100644 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -285,13 +285,27 @@ END_EXTERN_C() #define php_stream_from_res_no_verify(xstr, pzval) (xstr) = (php_stream*)zend_fetch_resource2((res), "stream", php_file_le_stream(), php_file_le_pstream()) #define php_stream_from_zval_no_verify(xstr, pzval) (xstr) = (php_stream*)zend_fetch_resource2_ex((pzval), "stream", php_file_le_stream(), php_file_le_pstream()) +static zend_always_inline php_stream* php_stream_from_zval_no_verify_no_error(zval *zval) { + return (php_stream*)zend_fetch_resource2_ex(zval, NULL, php_file_le_stream(), php_file_le_pstream()); +} + BEGIN_EXTERN_C() -static zend_always_inline bool php_stream_zend_parse_arg_into_stream(zval *arg, php_stream **destination_stream_ptr, bool check_null) -{ +static zend_always_inline bool php_stream_zend_parse_arg_into_stream( + zval *arg, + php_stream **destination_stream_ptr, + bool check_null, + uint32_t arg_num +) { if (EXPECTED(Z_TYPE_P(arg) == IS_RESOURCE)) { - *destination_stream_ptr = (php_stream*)zend_fetch_resource2(Z_RES_P(arg), "stream", php_file_le_stream(), php_file_le_pstream()); - if (UNEXPECTED(*destination_stream_ptr == NULL)) { + zend_resource *res = Z_RES_P(arg); + /* We do not use zend_fetch_resource2() API, + * as we want to be able to specify the argument number in the type error */ + if (EXPECTED(res->type == php_file_le_stream() || res->type == php_file_le_pstream())) { + *destination_stream_ptr = (php_stream*)res->ptr; + return true; + } else { + zend_argument_type_error(arg_num, "must be an open stream resource"); return false; } } else if (check_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) { @@ -304,7 +318,7 @@ static zend_always_inline bool php_stream_zend_parse_arg_into_stream(zval *arg, #define PHP_Z_PARAM_STREAM_EX(destination_stream_ptr, check_null) \ Z_PARAM_PROLOGUE(0, 0); \ - if (UNEXPECTED(!php_stream_zend_parse_arg_into_stream(_arg, &destination_stream_ptr, check_null))) { \ + if (UNEXPECTED(!php_stream_zend_parse_arg_into_stream(_arg, &destination_stream_ptr, check_null, _i))) { \ _error_code = ZPP_ERROR_FAILURE; \ if (!EG(exception)) { \ _expected_type = check_null ? Z_EXPECTED_RESOURCE_OR_NULL : Z_EXPECTED_RESOURCE; \ diff --git a/main/streams/php_stream_context.h b/main/streams/php_stream_context.h index d4ebe29bc162e..a5325a94642c9 100644 --- a/main/streams/php_stream_context.h +++ b/main/streams/php_stream_context.h @@ -25,14 +25,17 @@ typedef void (*php_stream_notification_func)(php_stream_context *context, #define PHP_STREAM_NOTIFIER_PROGRESS 1 +/* TODO: Remove dependence on ext/standard/file.h for the default context global */ +#define php_stream_context_get_default(without_context) \ + (without_context) ? NULL : FG(default_context) ? FG(default_context) : \ + (FG(default_context) = php_stream_context_alloc()) + /* Attempt to fetch context from the zval passed, If no context was passed, use the default context The default context has not yet been created, do it now. */ #define php_stream_context_from_zval(zcontext, nocontext) ( \ (zcontext) ? zend_fetch_resource_ex(zcontext, "Stream-Context", php_le_stream_context()) : \ - (nocontext) ? NULL : \ - FG(default_context) ? FG(default_context) : \ - (FG(default_context) = php_stream_context_alloc()) ) + php_stream_context_get_default(nocontext)) #define php_stream_context_to_zval(context, zval) { ZVAL_RES(zval, (context)->res); GC_ADDREF((context)->res); } @@ -53,6 +56,7 @@ struct _php_stream_context { }; BEGIN_EXTERN_C() +PHPAPI int php_le_stream_context(void); PHPAPI void php_stream_context_free(php_stream_context *context); PHPAPI php_stream_context *php_stream_context_alloc(void); PHPAPI zval *php_stream_context_get_option(php_stream_context *context, diff --git a/main/streams/streams.c b/main/streams/streams.c index e83acd5f7e161..661a0da9c883c 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1390,6 +1390,10 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence) } whence = SEEK_SET; break; + case SEEK_SET: + if (offset < 0) { + return -1; + } } ret = stream->ops->seek(stream, offset, whence, &stream->position); diff --git a/php.ini-development b/php.ini-development index 37619fd071c55..162fb3f25c19c 100644 --- a/php.ini-development +++ b/php.ini-development @@ -817,6 +817,12 @@ enable_dl = Off ; https://php.net/fastcgi.impersonate ;fastcgi.impersonate = 1 +; Prevent decoding of SCRIPT_FILENAME when using Apache ProxyPass or +; ProxyPassMatch. This should only be used if script file paths are already +; stored in an encoded format on the file system. +; Default is 0. +;fastcgi.script_path_encoded = 1 + ; Disable logging through FastCGI connection. PHP's default behavior is to enable ; this feature. ;fastcgi.logging = 0 diff --git a/php.ini-production b/php.ini-production index 60069f69b8b90..042d246943d81 100644 --- a/php.ini-production +++ b/php.ini-production @@ -819,6 +819,12 @@ enable_dl = Off ; https://php.net/fastcgi.impersonate ;fastcgi.impersonate = 1 +; Prevent decoding of SCRIPT_FILENAME when using Apache ProxyPass or +; ProxyPassMatch. This should only be used if script file paths are already +; stored in an encoded format on the file system. +; Default is 0. +;fastcgi.script_path_encoded = 1 + ; Disable logging through FastCGI connection. PHP's default behavior is to enable ; this feature. ;fastcgi.logging = 0 diff --git a/run-tests.php b/run-tests.php index 0db6937c7a848..a90681c7ff7f1 100755 --- a/run-tests.php +++ b/run-tests.php @@ -1934,6 +1934,7 @@ function run_test(string $php, $file, array $env): string $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff'; $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log'; $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp'; + $stdin_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'stdin'; $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out'; $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem'; $sh_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'sh'; @@ -1972,6 +1973,7 @@ function run_test(string $php, $file, array $env): string @unlink($diff_filename); @unlink($log_filename); @unlink($exp_filename); + @unlink($stdin_filename); @unlink($output_filename); @unlink($memcheck_filename); @unlink($sh_filename); @@ -2696,6 +2698,16 @@ function run_test(string $php, $file, array $env): string $diff = generate_diff($wanted, $wanted_re, $output); } + // write .stdin + if ($test->hasSection('STDIN') || $test->hasSection('PHPDBG')) { + $stdin = $test->hasSection('STDIN') + ? $test->getSection('STDIN') + : $test->getSection('PHPDBG') . "\n"; + if (file_put_contents($stdin_filename, $stdin) === false) { + error("Cannot create test stdin - $stdin_filename"); + } + } + if (is_array($IN_REDIRECT)) { $orig_shortname = str_replace(TEST_PHP_SRCDIR . '/', '', $file); $diff = "# original source file: $orig_shortname\n" . $diff; diff --git a/sapi/embed/config.m4 b/sapi/embed/config.m4 index c385e289a70ee..2bb5ed4df4da4 100644 --- a/sapi/embed/config.m4 +++ b/sapi/embed/config.m4 @@ -11,7 +11,10 @@ if test "$PHP_EMBED" != "no"; then AS_CASE([$PHP_EMBED], [yes|shared], [ LIBPHP_CFLAGS="-shared" - PHP_EMBED_TYPE=shared + AS_CASE(["$host_alias"], [*darwin*], [ + SAPI_SHARED="libs/libphp.dylib" + PHP_EMBED_TYPE=shared-dylib + ], [PHP_EMBED_TYPE=shared]) INSTALL_IT="\$(mkinstalldirs) \$(INSTALL_ROOT)\$(orig_libdir); \$(INSTALL) -m 0755 $SAPI_SHARED \$(INSTALL_ROOT)\$(orig_libdir)" ], [static], [ diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index 12edcedd951df..8af1e51d512fb 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -144,6 +144,7 @@ typedef struct _php_cgi_globals_struct { bool nph; bool fix_pathinfo; bool discard_path; + bool fcgi_script_path_encoded; bool fcgi_logging; bool fcgi_logging_request_started; HashTable user_config_cache; @@ -1066,6 +1067,10 @@ static void init_request_info(void) } } + if (apache_was_here && !CGIG(fcgi_script_path_encoded)) { + php_raw_url_decode(env_script_filename, strlen(env_script_filename)); + } + if (CGIG(fix_pathinfo)) { struct stat st; char *real_path = NULL; @@ -1174,7 +1179,7 @@ static void init_request_info(void) * it is probably also in SCRIPT_NAME and need to be removed */ size_t decoded_path_info_len = 0; - if (strchr(path_info, '%')) { + if (CGIG(fcgi_script_path_encoded) && strchr(path_info, '%')) { decoded_path_info = estrdup(path_info); decoded_path_info_len = php_raw_url_decode(decoded_path_info, strlen(path_info)); } @@ -1421,13 +1426,14 @@ static void fastcgi_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_ /* }}} */ PHP_INI_BEGIN() - STD_PHP_INI_BOOLEAN("cgi.rfc2616_headers", "0", PHP_INI_ALL, OnUpdateBool, rfc2616_headers, php_cgi_globals_struct, php_cgi_globals) - STD_PHP_INI_BOOLEAN("cgi.nph", "0", PHP_INI_ALL, OnUpdateBool, nph, php_cgi_globals_struct, php_cgi_globals) - STD_PHP_INI_BOOLEAN("cgi.fix_pathinfo", "1", PHP_INI_SYSTEM, OnUpdateBool, fix_pathinfo, php_cgi_globals_struct, php_cgi_globals) - STD_PHP_INI_BOOLEAN("cgi.discard_path", "0", PHP_INI_SYSTEM, OnUpdateBool, discard_path, php_cgi_globals_struct, php_cgi_globals) - STD_PHP_INI_BOOLEAN("fastcgi.logging", "1", PHP_INI_SYSTEM, OnUpdateBool, fcgi_logging, php_cgi_globals_struct, php_cgi_globals) - STD_PHP_INI_ENTRY("fastcgi.error_header", NULL, PHP_INI_SYSTEM, OnUpdateString, error_header, php_cgi_globals_struct, php_cgi_globals) - STD_PHP_INI_ENTRY("fpm.config", NULL, PHP_INI_SYSTEM, OnUpdateString, fpm_config, php_cgi_globals_struct, php_cgi_globals) + STD_PHP_INI_BOOLEAN("cgi.rfc2616_headers", "0", PHP_INI_ALL, OnUpdateBool, rfc2616_headers, php_cgi_globals_struct, php_cgi_globals) + STD_PHP_INI_BOOLEAN("cgi.nph", "0", PHP_INI_ALL, OnUpdateBool, nph, php_cgi_globals_struct, php_cgi_globals) + STD_PHP_INI_BOOLEAN("cgi.fix_pathinfo", "1", PHP_INI_SYSTEM, OnUpdateBool, fix_pathinfo, php_cgi_globals_struct, php_cgi_globals) + STD_PHP_INI_BOOLEAN("cgi.discard_path", "0", PHP_INI_SYSTEM, OnUpdateBool, discard_path, php_cgi_globals_struct, php_cgi_globals) + STD_PHP_INI_BOOLEAN("fastcgi.script_path_encoded", "0", PHP_INI_SYSTEM, OnUpdateBool, fcgi_script_path_encoded, php_cgi_globals_struct, php_cgi_globals) + STD_PHP_INI_BOOLEAN("fastcgi.logging", "1", PHP_INI_SYSTEM, OnUpdateBool, fcgi_logging, php_cgi_globals_struct, php_cgi_globals) + STD_PHP_INI_ENTRY("fastcgi.error_header", NULL, PHP_INI_SYSTEM, OnUpdateString, error_header, php_cgi_globals_struct, php_cgi_globals) + STD_PHP_INI_ENTRY("fpm.config", NULL, PHP_INI_SYSTEM, OnUpdateString, fpm_config, php_cgi_globals_struct, php_cgi_globals) PHP_INI_END() /* {{{ php_cgi_globals_ctor */ @@ -1437,6 +1443,7 @@ static void php_cgi_globals_ctor(php_cgi_globals_struct *php_cgi_globals) php_cgi_globals->nph = 0; php_cgi_globals->fix_pathinfo = 1; php_cgi_globals->discard_path = 0; + php_cgi_globals->fcgi_script_path_encoded = 0; php_cgi_globals->fcgi_logging = 1; php_cgi_globals->fcgi_logging_request_started = false; zend_hash_init(&php_cgi_globals->user_config_cache, 0, NULL, user_config_cache_entry_dtor, 1); diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c index d93459b4ea370..fb02a3e191775 100644 --- a/sapi/fpm/fpm/fpm_php.c +++ b/sapi/fpm/fpm/fpm_php.c @@ -93,7 +93,21 @@ int fpm_php_apply_defines_ex(struct key_value_s *kv, int mode) /* {{{ */ if (!strcmp(name, "extension") && *value) { zval zv; zend_interned_strings_switch_storage(0); + +#if ZEND_RC_DEBUG + bool orig_rc_debug = zend_rc_debug; + /* Loading extensions after php_module_startup() breaks some invariants. + * For instance, it will update the refcount of persistent strings, + * which is normally not allowed at this stage. */ + zend_rc_debug = false; +#endif + php_dl(value, MODULE_PERSISTENT, &zv, 1); + +#if ZEND_RC_DEBUG + zend_rc_debug = orig_rc_debug; +#endif + zend_interned_strings_switch_storage(1); return Z_TYPE(zv) == IS_TRUE ? FPM_PHP_INI_EXTENSION_LOADED : FPM_PHP_INI_EXTENSION_FAILED; } diff --git a/sapi/fpm/tests/fcgi-env-pif-apache-pp-sfp-decoding.phpt b/sapi/fpm/tests/fcgi-env-pif-apache-pp-sfp-decoding.phpt new file mode 100644 index 0000000000000..d6189107fb84b --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-pif-apache-pp-sfp-decoding.phpt @@ -0,0 +1,54 @@ +--TEST-- +FPM: FastCGI change for Apache ProxyPass SCRIPT_FILENAME decoding (GH-17645) +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName('+'); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + uri: $scriptName . '/1%202', + scriptFilename: "proxy:fcgi://" . $tester->getAddr() . str_replace('+', '%2B', $sourceFilePath) . '/1%202', + scriptName: $scriptName . '/1 2' + ) + ->expectBody([$scriptName, $scriptName . '/1 2', $sourceFilePath, '/1 2', $scriptName . '/1 2']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-pif-apache-pp-sfp-encoded.phpt b/sapi/fpm/tests/fcgi-env-pif-apache-pp-sfp-encoded.phpt new file mode 100644 index 0000000000000..3b5ccc86b6926 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-pif-apache-pp-sfp-encoded.phpt @@ -0,0 +1,55 @@ +--TEST-- +FPM: FastCGI change for Apache ProxyPass SCRIPT_FILENAME decoding - fallback (GH-17645) +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName('%2B'); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + uri: $scriptName . '/1%202', + scriptFilename: "proxy:fcgi://" . $tester->getAddr() . $sourceFilePath . '/1%202', + scriptName: $scriptName . '/1 2' + ) + ->expectBody([$scriptName, $scriptName . '/1 2', $sourceFilePath, '/1 2', $scriptName . '/1 2']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/tester.inc b/sapi/fpm/tests/tester.inc index 8e67d17430a64..f486309085e6d 100644 --- a/sapi/fpm/tests/tester.inc +++ b/sapi/fpm/tests/tester.inc @@ -47,7 +47,7 @@ class Tester self::FILE_EXT_LOG_ERR, self::FILE_EXT_LOG_SLOW, self::FILE_EXT_PID, - 'src.php', + '*src.php', 'ini', 'skip.ini', '*.sock', @@ -107,6 +107,11 @@ class Tester */ private string $fileName; + /** + * @var string + */ + private ?string $sourceFile = null; + /** * @var resource */ @@ -1483,21 +1488,27 @@ class Tester /** * Create a source code file. * + * @param string $nameSuffix * @return string */ - public function makeSourceFile(): string + public function makeSourceFile(string $nameSuffix = ''): string { - return $this->makeFile('src.php', $this->code, overwrite: false); + if (is_null($this->sourceFile)) { + $this->sourceFile = $this->makeFile($nameSuffix . 'src.php', $this->code, overwrite: false); + } + + return $this->sourceFile; } /** * Create a source file and script name. * + * @param string $nameSuffix * @return string[] */ - public function createSourceFileAndScriptName(): array + public function createSourceFileAndScriptName(string $nameSuffix = ''): array { - $sourceFile = $this->makeFile('src.php', $this->code, overwrite: false); + $sourceFile = $this->makeSourceFile($nameSuffix); return [$sourceFile, '/' . basename($sourceFile)]; } diff --git a/sapi/fuzzer/fuzzer-json.c b/sapi/fuzzer/fuzzer-json.c index 930f136a47236..78c8505c2f1dc 100644 --- a/sapi/fuzzer/fuzzer-json.c +++ b/sapi/fuzzer/fuzzer-json.c @@ -15,8 +15,6 @@ +----------------------------------------------------------------------+ */ - - #include "fuzzer.h" #include "Zend/zend.h" @@ -31,14 +29,15 @@ #include "ext/json/php_json_parser.h" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - char *data = malloc(Size+1); - memcpy(data, Data, Size); - data[Size] = '\0'; - if (fuzzer_request_startup() == FAILURE) { + if (fuzzer_request_startup() == FAILURE){ return 0; } + char *data = malloc(Size + 1); + memcpy(data, Data, Size); + data[Size] = '\0'; + for (int option = 0; option <=1; ++option) { zval result; php_json_parser parser; diff --git a/sapi/fuzzer/fuzzer-mbregex.c b/sapi/fuzzer/fuzzer-mbregex.c index 451b19d99e310..f96e593ba8d24 100644 --- a/sapi/fuzzer/fuzzer-mbregex.c +++ b/sapi/fuzzer/fuzzer-mbregex.c @@ -30,15 +30,16 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { #ifdef HAVE_MBREGEX - char *args[2]; - char *data = malloc(Size+1); - memcpy(data, Data, Size); - data[Size] = '\0'; if (fuzzer_request_startup() == FAILURE) { return 0; } + char *args[2]; + char *data = malloc(Size+1); + memcpy(data, Data, Size); + data[Size] = '\0'; + fuzzer_setup_dummy_frame(); args[0] = data; diff --git a/sapi/fuzzer/fuzzer-unserialize.c b/sapi/fuzzer/fuzzer-unserialize.c index 023a19fbd08d3..8a889883a97d8 100644 --- a/sapi/fuzzer/fuzzer-unserialize.c +++ b/sapi/fuzzer/fuzzer-unserialize.c @@ -30,14 +30,15 @@ #include "ext/standard/php_var.h" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - unsigned char *orig_data = malloc(Size+1); - memcpy(orig_data, Data, Size); - orig_data[Size] = '\0'; if (fuzzer_request_startup() == FAILURE) { return 0; } + unsigned char *orig_data = malloc(Size+1); + memcpy(orig_data, Data, Size); + orig_data[Size] = '\0'; + fuzzer_setup_dummy_frame(); { diff --git a/sapi/fuzzer/fuzzer-unserializehash.c b/sapi/fuzzer/fuzzer-unserializehash.c index 90d874aba88cc..447e95d0ee815 100644 --- a/sapi/fuzzer/fuzzer-unserializehash.c +++ b/sapi/fuzzer/fuzzer-unserializehash.c @@ -34,15 +34,15 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t FullSize) { } ++Start; + if (fuzzer_request_startup() == FAILURE) { + return 0; + } + size_t Size = (Data + FullSize) - Start; unsigned char *orig_data = malloc(Size+1); memcpy(orig_data, Start, Size); orig_data[Size] = '\0'; - if (fuzzer_request_startup() == FAILURE) { - return 0; - } - fuzzer_setup_dummy_frame(); { diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c index 259d4a985cc66..a135e031b24d0 100644 --- a/sapi/litespeed/lsapi_main.c +++ b/sapi/litespeed/lsapi_main.c @@ -1678,11 +1678,11 @@ PHP_FUNCTION(litespeed_response_headers) char headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH]; if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + RETURN_THROWS(); + } - if (!&SG(sapi_headers).headers) { - RETURN_FALSE; + if (!zend_llist_count(&SG(sapi_headers).headers)) { + RETURN_FALSE; } array_init(return_value); diff --git a/sapi/litespeed/lscriu.c b/sapi/litespeed/lscriu.c index 1eb468fdf28cc..409fe989b5551 100644 --- a/sapi/litespeed/lscriu.c +++ b/sapi/litespeed/lscriu.c @@ -658,7 +658,7 @@ static int LSCRIU_Init_Env_Parameters(void) } -void LSCRIU_inc_req_processed() +void LSCRIU_inc_req_processed(void) { if (!LSCRIU_Get_Global_Counter_Type()) { ++s_requests_count; diff --git a/sapi/phpdbg/tests/watch_006.phpt b/sapi/phpdbg/tests/watch_006.phpt index 5b5ca9ee57c0e..c5f53a37510c5 100644 --- a/sapi/phpdbg/tests/watch_006.phpt +++ b/sapi/phpdbg/tests/watch_006.phpt @@ -2,9 +2,7 @@ Test multiple watch elements pointing to the same watchpoint --SKIPIF-- > self._info_shift) & self._gc_color - match gc_color: - case self._gc_black: - names.append('GC_BLACK') - case self._gc_white: - names.append('GC_WHITE') - case self._gc_grey: - names.append('GC_GREY') - case self._gc_purple: - names.append('GC_PURPLE') + if gc_color == self._gc_black: + names.append('GC_BLACK') + elif gc_color == self._gc_white: + names.append('GC_WHITE') + elif gc_color == self._gc_grey: + names.append('GC_GREY') + elif gc_color == self._gc_purple: + names.append('GC_PURPLE') gc_address = (flags >> self._info_shift) & self._gc_address if gc_address != 0: @@ -905,17 +904,16 @@ def _load(self): pattern = re.compile(r'#define (GC_[^\s]+)\s+((0x)?[0-9a-f]+)') matches = pattern.findall(content) for name, bit, _ in matches: - match name: - case 'GC_TYPE_MASK': - self._type_mask = int(bit, 0) - case 'GC_FLAGS_MASK': - self._flags_mask = int(bit, 0) - case 'GC_INFO_MASK': - self._info_mask = int(bit, 0) - case 'GC_INFO_SHIFT': - self._info_shift = int(bit, 0) - case 'GC_FLAGS_SHIFT': - self._flags_shift = int(bit, 0) + if name == 'GC_TYPE_MASK': + self._type_mask = int(bit, 0) + elif name == 'GC_FLAGS_MASK': + self._flags_mask = int(bit, 0) + elif name == 'GC_INFO_MASK': + self._info_mask = int(bit, 0) + elif name == 'GC_INFO_SHIFT': + self._info_shift = int(bit, 0) + elif name == 'GC_FLAGS_SHIFT': + self._flags_shift = int(bit, 0) # IS_STR_INTERNED GC_IMMUTABLE # IS_STR_PERMANENT (1<<8) @@ -926,13 +924,12 @@ def _load(self): bit = bits.get(val) if bit == None: continue - match type: - case 'STR': - target = str_bits - case 'ARRAY': - target = array_bits - case 'OBJ': - target = obj_bits + if type == 'STR': + target = str_bits + elif type == 'ARRAY': + target = array_bits + elif type == 'OBJ': + target = obj_bits target[name] = int(bit) # Hard coded because these are not exposed in header files diff --git a/win32/build/config.w32 b/win32/build/config.w32 index f82ed73efe3bd..c9da328e2e799 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -267,7 +267,11 @@ if (TARGET_ARCH == 'arm64') { DEFINE('FIBER_ASM_FLAGS', '/DBOOST_CONTEXT_EXPORT=EXPORT /nologo /c /Fo'); } -ADD_FLAG('ASM_OBJS', '$(BUILD_DIR)\\Zend\\jump_' + FIBER_ASM_ABI + '.obj $(BUILD_DIR)\\Zend\\make_' + FIBER_ASM_ABI + '.obj'); +var all_asm_objs = '$(BUILD_DIR)\\Zend\\jump_' + FIBER_ASM_ABI + '.obj $(BUILD_DIR)\\Zend\\make_' + FIBER_ASM_ABI + '.obj'; +if (TARGET_ARCH == 'x64') { + all_asm_objs += ' $(BUILD_DIR)\\Zend\\save_xmm_x86_64_ms_masm.obj'; +} +ADD_FLAG('ASM_OBJS', all_asm_objs); MFO.WriteLine('$(BUILD_DIR)\\Zend\\jump_' + FIBER_ASM_ABI + '.obj: Zend\\asm\\jump_' + FIBER_ASM_ABI + '.asm'); MFO.WriteLine('\t$(PHP_ASSEMBLER) $(FIBER_ASM_FLAGS) $(BUILD_DIR)\\Zend\\jump_$(FIBER_ASM_ABI).obj Zend\\asm\\jump_$(FIBER_ASM_ABI).asm'); @@ -275,6 +279,11 @@ MFO.WriteLine('\t$(PHP_ASSEMBLER) $(FIBER_ASM_FLAGS) $(BUILD_DIR)\\Zend\\jump_$( MFO.WriteLine('$(BUILD_DIR)\\Zend\\make_' + FIBER_ASM_ABI + '.obj: Zend\\asm\\make_' + FIBER_ASM_ABI + '.asm'); MFO.WriteLine('\t$(PHP_ASSEMBLER) $(FIBER_ASM_FLAGS) $(BUILD_DIR)\\Zend\\make_$(FIBER_ASM_ABI).obj Zend\\asm\\make_$(FIBER_ASM_ABI).asm'); +if (TARGET_ARCH == 'x64') { + MFO.WriteLine('$(BUILD_DIR)\\Zend\\save_xmm_x86_64_ms_masm.obj: Zend\\asm\\save_xmm_x86_64_ms_masm.asm'); + MFO.WriteLine('\t$(PHP_ASSEMBLER) $(FIBER_ASM_FLAGS) $(BUILD_DIR)\\Zend\\save_xmm_x86_64_ms_masm.obj Zend\\asm\\save_xmm_x86_64_ms_masm.asm'); +} + ADD_FLAG("CFLAGS_BD_ZEND", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); if (VS_TOOLSET && VCVERS >= 1914) { ADD_FLAG("CFLAGS_BD_ZEND", "/d2FuncCache1");