From f1fc4e8ff7075781ffed916eee05a6e240b5185f Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 27 Nov 2024 20:31:37 +0100 Subject: [PATCH 01/13] Fix GH-16957: Assertion failure in array_shift with self-referencing array We have an RC1 violation because we're immediately dereferencing and copying the resulting array in the test case. Instead, transfer the lifetime using RETVAL_COPY_VALUE and unwrap only after the internal iterator is reset. Closes GH-16970. --- NEWS | 2 ++ ext/standard/array.c | 10 +++++-- ext/standard/tests/array/gh16957.phpt | 41 +++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 ext/standard/tests/array/gh16957.phpt diff --git a/NEWS b/NEWS index aba1f7a76ca14..f535cf7187c7a 100644 --- a/NEWS +++ b/NEWS @@ -76,6 +76,8 @@ PHP NEWS - Standard: . Fixed bug GH-16905 (Internal iterator functions can't handle UNDEF properties). (nielsdos) + . Fixed bug GH-16957 (Assertion failure in array_shift with + self-referencing array). (nielsdos) - Streams: . Fixed network connect poll interuption handling. (Jakub Zelenka) diff --git a/ext/standard/array.c b/ext/standard/array.c index 73ba7e5d7a488..7382e1e9f8bd9 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -3511,7 +3511,8 @@ PHP_FUNCTION(array_shift) } idx++; } - RETVAL_COPY_DEREF(val); + RETVAL_COPY_VALUE(val); + ZVAL_UNDEF(val); /* Delete the first value */ zend_hash_packed_del_val(Z_ARRVAL_P(stack), val); @@ -3565,7 +3566,8 @@ PHP_FUNCTION(array_shift) } idx++; } - RETVAL_COPY_DEREF(val); + RETVAL_COPY_VALUE(val); + ZVAL_UNDEF(val); /* Delete the first value */ zend_hash_del_bucket(Z_ARRVAL_P(stack), p); @@ -3589,6 +3591,10 @@ PHP_FUNCTION(array_shift) } zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack)); + + if (Z_ISREF_P(return_value)) { + zend_unwrap_reference(return_value); + } } /* }}} */ diff --git a/ext/standard/tests/array/gh16957.phpt b/ext/standard/tests/array/gh16957.phpt new file mode 100644 index 0000000000000..a716228249e7d --- /dev/null +++ b/ext/standard/tests/array/gh16957.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-16957 (Assertion failure in array_shift with self-referencing array) +--FILE-- + 1, 300 => 'two'); +var_dump($shifted = array_shift($new_array2)); +var_dump($new_array2); +var_dump($new_array2 === $shifted); +?> +--EXPECT-- +array(2) { + [0]=> + int(1) + [1]=> + string(3) "two" +} +array(2) { + [0]=> + int(1) + [1]=> + string(3) "two" +} +bool(true) +array(2) { + [0]=> + int(1) + [1]=> + string(3) "two" +} +array(2) { + [0]=> + int(1) + [1]=> + string(3) "two" +} +bool(true) From 1668a1602afb8ba7700e35bc3e8c09d4113aef49 Mon Sep 17 00:00:00 2001 From: hakre Date: Fri, 29 Nov 2024 19:29:00 +0100 Subject: [PATCH 02/13] Improve php-src docs sphinx build, also on *nix (GH-16743) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Document .rst file maximum line length of 100 In 19d2b84788 ("Create book for docs", 2024-01-30) the build of the php-src documentation has been introduced. It is based on reStructuredText (rst) [Docutils] for its source files, this stems from the sphinx-build utility in use to build the static HTML pages of the php-src documentation. The maximum line length of these text files has been set to 100 characters in 19d2b84788 ("Create book for docs", 2024-01-30), the rationale is unknown to the documenting author at time of writing this message. This formatting constraint is applied with the rstfmt utility [rstfmt] via its invocation (documented in CI build instructions and README.md:) rstfmt -w 100 source The `-w, --width` option takes a WIDTH argument that is "the target line length in characters" (cf. `rstfmt --help`.) There is also an `--ext EXT` argument option, that is "the extension of files to look at when passed a directory" ("source" is the name of a directory in the invocation above) and defaults to "rst". Henceforth, the editor configuration [EditorConfig] can benefit from documenting this expectation in the repositories .editorconfig file, which has been introduced already earlier in 5c38fbe543 ("Added editorconfig file", 2016-06-26). [Docutils]: https://docutils.sourceforge.io/index.html "Docutils: Documentation Utilities — Written in Python, for General- and Special-Purpose Use" [rstfmt]: https://github.com/dzhu/rstfmt "A formatter for reStructuredText" [EditorConfig]: https://editorconfig.org/ "EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs" * Makefile for php-src docs build In 19d2b84788 ("Create book for docs", 2024-01-30) the php-src documentation (php-src docs) build has been introduced, yet the build instructions, namely `make html`, did not yield the expected results within the parenting setup of the php-src project on *nix systems. The reason is that the `make html` build instruction does not execute the make.bat file which contains the recipe to build the static HTML pages. It is an unused leftover file from initializing the project with sphinx-quickstart. [1] Removing it in and adding a Makefile suffices to recover the build of php-src ./docs on a *nix system. Formatting constraints checked in the docs workflow in CI update use the make file to make sure the commands stay consistent and the build is managed by the build manager. [1]: https://www.sphinx-doc.org/en/master/man/sphinx-quickstart.html "sphinx-quickstart is an interactive tool that asks some questions about your project and then generates a complete documentation directory and sample Makefile to be used with sphinx-build(1)." * Bind requirements.txt for php-src docs build Define the required packages to install for the php-src docs build in the docs/requirements.txt file: 1) Sphinx 2) sphinx-design 3) sphinxawesome-theme 4) rstfmt This should also later on ease the use of a requirements_frozen.txt file to pin the build dependencies if needed/wanted. Additionally, some formatting corrections in README.md (based on the profile in .editorconfig) as well as adding the recommendation to use a Python virtual environment. Python3 and Pip were already named, and with Python3 there is the venv module (Python 3.3; Sep 2012) to manage these so-called python virtual environments [venv], which are commonly a preferred way to install dependencies within development projects and build systems. [venv]: https://docs.python.org/3/library/venv.html "venv — Creation of virtual environments — Python documentation" * Remove deprecated theme configuration For the configured Awesome Sphinx Theme [1] highlighting extension, the sphinx-build currently yields the following diagnostics: WARNING: while setting up extension sphinxawesome_theme.highlighting: \ You no longer have to include the `sphinxawsome_theme.highlighting` \ extension. This extension will be removed in the next major release. (via `make html`, the configuration file is `source/conf.py`.) The diagnostic message was introduced by sphinxawesome-theme 5.2.0, released May 31, 2024. [2], [3] Removing the extension from the list of extensions in the configuration file levitates. No changes to requirements.txt, the extension was transitive as bundled by the Awesome Sphinx Theme [1], and 5.2.0 deprecates it with the new feature to "Support `pygments_style_dark` option that allows you to set a different syntax highlighting scheme in light and dark modes." [3] [1]: https://sphinxawesome.xyz/ "Awesome Sphinx Theme — Create functional and beautiful websites for your documentation with Sphinx." [2]: https://pypi.org/project/sphinxawesome-theme/5.2.0/#history [3]: https://github.com/kai687/sphinxawesome-theme/releases/tag/5.2.0 --- .editorconfig | 4 ++++ .github/workflows/docs.yml | 4 ++-- docs/Makefile | 36 ++++++++++++++++++++++++++++++++++++ docs/README.md | 19 ++++++++++++------- docs/make.bat | 35 ----------------------------------- docs/requirements.txt | 4 ++++ docs/source/conf.py | 1 - 7 files changed, 58 insertions(+), 45 deletions(-) create mode 100644 docs/Makefile delete mode 100644 docs/make.bat create mode 100644 docs/requirements.txt diff --git a/.editorconfig b/.editorconfig index 7911bf8490b63..19be96087d908 100644 --- a/.editorconfig +++ b/.editorconfig @@ -32,3 +32,7 @@ max_line_length = 80 [*.patch] trim_trailing_whitespace = false + +[*.rst] +indent_style = space +max_line_length = 100 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 2254b8f037e54..6ae972d92e49c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -19,9 +19,9 @@ jobs: - name: git checkout uses: actions/checkout@v4 - name: Install dependencies - run: pip install sphinx-design sphinxawesome-theme rstfmt + run: pip install -r docs/requirements.txt - name: Check formatting - run: rstfmt --check -w 100 docs/source + run: make -C docs check-formatting - name: Publish if: github.event_name == 'push' uses: sphinx-notes/pages@v3 diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000000000..12f3a0600a949 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,36 @@ +# Makefile for php-src/docs +# Copyright (c) The PHP Group + +# If people set these on the make command line, use 'em + +SPHINXBUILD ?= sphinx-build + +SOURCEDIR = source +BUILDDIR = build +RSTFMT = rstfmt +RSTFMTFLAGS = -w 100 + +rwildcard = $(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) +FILES = $(call rwildcard,$(SOURCEDIR),*.rst) + +all : html + +.PHONY : check-formatting clean html preflight +.SUFFIXES : # Disable legacy behavior + +check-formatting : + $(RSTFMT) $(RSTFMTFLAGS) --check $(SOURCEDIR) + +clean : + rm -rf -- $(wildcard $(SOURCEDIR)/.~ $(BUILDDIR)) + +html : preflight + $(SPHINXBUILD) -M $@ $(SOURCEDIR) $(BUILDDIR) + @printf 'Browse the \e]8;;%s\e\\%s\e]8;;\e\\.\n' \ + "file://$(abspath $(BUILDDIR))/$@/index.$@" "php-src html docs locally" + +preflight : $(SOURCEDIR)/.~ + +$(SOURCEDIR)/.~ : $(FILES) + $(RSTFMT) $(RSTFMTFLAGS) $? + touch $@ diff --git a/docs/README.md b/docs/README.md index fbd58155a5141..3c0d7ddd2bcc3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,9 +1,10 @@ # php-src docs This is the home of the php-src internal documentation, hosted at -[php.github.io/php-src/](https://php.github.io/php-src/). It is in very early stages, but is -intended to become the primary place where new information about php-src is documented. Over time, -it is expected to replace various mediums like: +[php.github.io/php-src/](https://php.github.io/php-src/). It is in very early +stages, but is intended to become the primary place where new information about +php-src is documented. Over time, it is expected to replace various mediums +like: * https://www.phpinternalsbook.com/ * https://wiki.php.net/internals @@ -14,11 +15,15 @@ it is expected to replace various mediums like: `python` 3 and `pip` are required. ```bash -pip install sphinx sphinx-design sphinxawesome-theme +cd docs +# Recommended: Initialize and activate a Python virtual environment +pip install --upgrade pip +pip install -r requirements.txt make html ``` -That's it! You can view the documentation under `./build/html/index.html` in your browser. +That's it! You can view the documentation under `./build/html/index.html` in +your browser. ## Formatting @@ -29,5 +34,5 @@ The files in this documentation are formatted using the rstfmt -w 100 source ``` -This tool is not perfect. It breaks on custom directives, so we might switch to either a fork or -something else in the future. +This tool is not perfect. It breaks on custom directives, so we might switch to +either a fork or something else in the future. diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 747ffb7b30336..0000000000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "" goto help - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000000000..ca19fe15c2e05 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,4 @@ +Sphinx +sphinx-design +sphinxawesome-theme +rstfmt diff --git a/docs/source/conf.py b/docs/source/conf.py index 2eb75d509cc07..1129eb08a8216 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -16,7 +16,6 @@ author = 'The PHP Group' extensions = [ 'sphinx_design', - 'sphinxawesome_theme.highlighting', ] templates_path = ['_templates'] html_theme = 'sphinxawesome_theme' From 94fa2a4ce103eaa3ac745e2f3d920b81bd60dc18 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 29 Nov 2024 19:43:07 +0100 Subject: [PATCH 03/13] Fix potential OOB read in zend_dirname() on Windows Only on Windows `IS_SLASH_P()` may read the previous byte, and so may in unlikely cases read one byte out of bounds. Since `IS_SLASH_P()` is in a public header (albeit not likely to be used by external extensions or SAPIs), we introduce `IS_SLASH_P_EX()` which accepts a second argument to prevent that OOB read. It should be noted that the PHP userland function `dirname()` is not affected by this issue, since it does not call `zend_dirname()` on Windows. Closes GH-16995. --- NEWS | 1 + Zend/zend_compile.c | 6 +++--- Zend/zend_virtual_cwd.h | 5 +++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index eca09704cfc59..84fdaf00b4876 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,7 @@ PHP NEWS . Fixed bug GH-16630 (UAF in lexer with encoding translation and heredocs). (nielsdos) . Fix is_zend_ptr() huge block comparison. (nielsdos) + . Fixed potential OOB read in zend_dirname() on Windows. (cmb) - Curl: . Fix various memory leaks in curl mime handling. (nielsdos) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 38d378a4175bb..52b3417234cf7 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1997,7 +1997,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len) } /* Strip trailing slashes */ - while (end >= path && IS_SLASH_P(end)) { + while (end >= path && IS_SLASH_P_EX(end, end == path)) { end--; } if (end < path) { @@ -2008,7 +2008,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len) } /* Strip filename */ - while (end >= path && !IS_SLASH_P(end)) { + while (end >= path && !IS_SLASH_P_EX(end, end == path)) { end--; } if (end < path) { @@ -2019,7 +2019,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len) } /* Strip slashes which came before the file name */ - while (end >= path && IS_SLASH_P(end)) { + while (end >= path && IS_SLASH_P_EX(end, end == path)) { end--; } if (end < path) { diff --git a/Zend/zend_virtual_cwd.h b/Zend/zend_virtual_cwd.h index 728e3ba69d888..28cbf6300b8ec 100644 --- a/Zend/zend_virtual_cwd.h +++ b/Zend/zend_virtual_cwd.h @@ -73,8 +73,11 @@ typedef unsigned short mode_t; #define DEFAULT_SLASH '\\' #define DEFAULT_DIR_SEPARATOR ';' #define IS_SLASH(c) ((c) == '/' || (c) == '\\') +// IS_SLASH_P() may read the previous char on Windows, which may be OOB; use IS_SLASH_P_EX() instead #define IS_SLASH_P(c) (*(c) == '/' || \ (*(c) == '\\' && !IsDBCSLeadByte(*(c-1)))) +#define IS_SLASH_P_EX(c, first_byte) (*(c) == '/' || \ + (*(c) == '\\' && ((first_byte) || !IsDBCSLeadByte(*(c-1))))) /* COPY_WHEN_ABSOLUTE is 2 under Win32 because by chance both regular absolute paths in the file system and UNC paths need copying of two characters */ @@ -98,7 +101,9 @@ typedef unsigned short mode_t; #endif #define IS_SLASH(c) ((c) == '/') +// IS_SLASH_P() may read the previous char on Windows, which may be OOB; use IS_SLASH_P_EX() instead #define IS_SLASH_P(c) (*(c) == '/') +#define IS_SLASH_P_EX(c, first_byte) IS_SLASH_P(c) #endif From 8b682743196e765debb5056e56a97a67304f5e62 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 26 Nov 2024 16:43:25 +0100 Subject: [PATCH 04/13] Fix method calls for PHP objects wrapped in variant As is, methods of PHP can never be called, because we're first trying to read the property with the name of the method. We fix this by first checking for `DISPATCH_METHOD` and treat that as method call, if the method would be callable. Only otherwise we try to access the respective property. It needs to be noted that this breaks code which accesses a property of an object, which defines a method of the same name. However, instances of such classes should never be wrapped in variants, because this can't be distinguished by COM anyway. Closes GH-16945. --- NEWS | 3 +- ext/com_dotnet/com_wrapper.c | 14 ++++--- ext/com_dotnet/tests/variant_variation3.phpt | 41 ++++++++++++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 ext/com_dotnet/tests/variant_variation3.phpt diff --git a/NEWS b/NEWS index 2bc7d6131aa81..fb54b6c67a15d 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,8 @@ PHP NEWS ?? ??? ????, PHP 8.5.0alpha1 - COM: - . Fix property access of PHP objects wrapped in variant. (cmb) + . Fixed property access of PHP objects wrapped in variant. (cmb) + . Fixed method calls for PHP objects wrapped in variant. (cmb) - Core: . Fixed bug GH-16665 (\array and \callable should not be usable in diff --git a/ext/com_dotnet/com_wrapper.c b/ext/com_dotnet/com_wrapper.c index 42698a2e651f5..81c31969161b8 100644 --- a/ext/com_dotnet/com_wrapper.c +++ b/ext/com_dotnet/com_wrapper.c @@ -257,13 +257,10 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex( /* TODO: if PHP raises an exception here, we should catch it * and expose it as a COM exception */ - if (wFlags & DISPATCH_PROPERTYGET) { - retval = zend_read_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), 1, &rv); - ret = S_OK; - } else if (wFlags & DISPATCH_PROPERTYPUT) { + if (wFlags & DISPATCH_PROPERTYPUT) { zend_update_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), ¶ms[0]); ret = S_OK; - } else if (wFlags & DISPATCH_METHOD) { + } else if (wFlags & DISPATCH_METHOD && zend_is_callable_ex(name, Z_OBJ(disp->object), 0, NULL, NULL, NULL)) { zend_try { retval = &rv; if (SUCCESS == call_user_function(NULL, &disp->object, name, @@ -289,6 +286,9 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex( trace("something blew up\n"); ret = DISP_E_EXCEPTION; } zend_end_try(); + } else if (wFlags & DISPATCH_PROPERTYGET) { + retval = zend_read_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), 1, &rv); + ret = S_OK; } else { trace("Don't know how to handle this invocation %08x\n", wFlags); } @@ -307,7 +307,9 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex( VariantInit(pvarRes); php_com_variant_from_zval(pvarRes, retval, COMG(code_page)); } - // zval_ptr_dtor(retval); // TODO needed for function calls? + if (retval == &rv) { + zval_ptr_dtor(retval); + } } else if (pvarRes) { VariantInit(pvarRes); } diff --git a/ext/com_dotnet/tests/variant_variation3.phpt b/ext/com_dotnet/tests/variant_variation3.phpt new file mode 100644 index 0000000000000..cb77f6982c871 --- /dev/null +++ b/ext/com_dotnet/tests/variant_variation3.phpt @@ -0,0 +1,41 @@ +--TEST-- +Testing reading properties and calling functions +--EXTENSIONS-- +com_dotnet +--FILE-- +foo); +var_dump($v->foo()); +var_dump($v->bar); +var_dump($v->bar()); +var_dump($v->stdclass); +var_dump($v->stdclass()); +try { + var_dump($v->qux); +} catch (com_exception $ex) { + echo $ex->getMessage(), "\n"; +} +?> +--EXPECTF-- +string(6) "method" +string(6) "method" +string(3) "bar" +string(3) "bar" +object(variant)#%d (0) { +} +object(variant)#%d (0) { +} +Unable to lookup `qux': %s From be69262137825d3559093df289b36b1da5f8ea31 Mon Sep 17 00:00:00 2001 From: DanielEScherzer Date: Sat, 30 Nov 2024 11:47:56 -0800 Subject: [PATCH 05/13] gen_stub: drop support for `@refcount 0` with scalar return (#16505) * gen_stub: drop support for `@refcount 0` with scalar return Currenty, if `@refcount` is omitted, it is assumed to be 0 for scalar return types and "N" otherwise. On the other hand, if `@refcount` is provided, for a scalar return type it *must* be 0, and for a non-scalar return type it *must not* be 0. In other words, the ref count will be 0 if and only if the return type is scalar, regardless of whether the `@refcount` tag is used. In that case, adding `@refcount 0` does nothing, and since its presence suggests it does something (why would a developer add code that does nothing?) it is confusing and should be removed. As it happens, there are currently no uses of `@refcount 0` in php-src, but why should we allow future uses? Removing this support also allows simplifying the code a bit. --- build/gen_stub.php | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 1468a0b68b164..800262f27e514 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -1159,8 +1159,7 @@ class ReturnInfo { const REFCOUNT_1 = "1"; const REFCOUNT_N = "N"; - const REFCOUNTS = [ - self::REFCOUNT_0, + const REFCOUNTS_NONSCALAR = [ self::REFCOUNT_1, self::REFCOUNT_N, ]; @@ -1204,16 +1203,14 @@ private function setRefcount(?string $refcount): void return; } - if (!in_array($refcount, ReturnInfo::REFCOUNTS, true)) { - throw new Exception("@refcount must have one of the following values: \"0\", \"1\", \"N\", $refcount given"); - } - - if ($isScalarType && $refcount !== self::REFCOUNT_0) { - throw new Exception('A scalar return type of "' . $type->__toString() . '" must have a refcount of "' . self::REFCOUNT_0 . '"'); + if ($isScalarType) { + throw new Exception( + "@refcount on functions returning scalar values is redundant and not permitted" + ); } - if (!$isScalarType && $refcount === self::REFCOUNT_0) { - throw new Exception('A non-scalar return type of "' . $type->__toString() . '" cannot have a refcount of "' . self::REFCOUNT_0 . '"'); + if (!in_array($refcount, ReturnInfo::REFCOUNTS_NONSCALAR, true)) { + throw new Exception("@refcount must have one of the following values: \"1\", \"N\", $refcount given"); } $this->refcount = $refcount; From b06f2bc67c3e47dfb686a8ef4e1e7a3447b9cd5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sat, 30 Nov 2024 22:48:21 +0100 Subject: [PATCH 06/13] Improve documentation generation - Really trim leading and trailing hyphens (single hyphens were not trimmed before) - Create the necesary directories for even namespaced methods when generating methodsynopsis --- build/gen_stub.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 800262f27e514..b105ed4efd8db 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -2610,7 +2610,7 @@ protected function getFieldSynopsisDefaultLinkend(): string { $className = str_replace(["\\", "_"], ["-", "-"], $this->name->class->toLowerString()); - return "$className.constants." . strtolower(str_replace(["__", "_"], ["", "-"], $this->name->getDeclarationName())); + return "$className.constants." . strtolower(str_replace("_", "-", trim($this->name->getDeclarationName(), "_"))); } protected function getFieldSynopsisName(): string @@ -3052,7 +3052,7 @@ protected function getFieldSynopsisDefaultLinkend(): string { $className = str_replace(["\\", "_"], ["-", "-"], $this->name->class->toLowerString()); - return "$className.props." . strtolower(str_replace(["__", "_"], ["", "-"], $this->name->getDeclarationName())); + return "$className.props." . strtolower(str_replace("_", "-", trim($this->name->getDeclarationName(), "_"))); } protected function getFieldSynopsisName(): string @@ -6424,8 +6424,14 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc } foreach ($methodSynopses as $filename => $content) { - if (!file_exists("$manualTarget/$filename")) { - if (file_put_contents("$manualTarget/$filename", $content)) { + $path = "$manualTarget/$filename"; + + if (!file_exists($path)) { + if (!file_exists(dirname($path))) { + mkdir(dirname($path)); + } + + if (file_put_contents($path, $content)) { echo "Saved $filename\n"; } } From aab784263d13dc56e8744260a0bc504435b012ef Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 30 Nov 2024 12:22:42 +0100 Subject: [PATCH 07/13] Fix GH-16998: UBSAN warning in rfc1867 The "else branch" of `next_line` can reset the `buf_begin` field to NULL, causing the next invocation to pass NULL to `memchr` with a 0 length. When UBSAN is enabled this causes an UBSAN abort. Real world impact is likely none because of the 0 length. To fix this, don't set the pointer to NULL, which means that the `memchr` will return NULL and since `self->bytes_in_buffer < self->bufsize` we return NULL and request more data through `fill_buffer`. That function will reset `buf_begin` and `bytes_in_buffer` so that the next invocation works fine. I chose this solution so we have an invariant that `buf_begin` is never NULL, which makes reasoning easier. An alternative solution is keeping the NULLing of `buf_begin` and add an extra check at the top of `next_line`, but I didn't like special casing this. Closes GH-17000. --- NEWS | 3 +++ main/rfc1867.c | 2 +- tests/basic/gh16998.phpt | 49 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tests/basic/gh16998.phpt diff --git a/NEWS b/NEWS index 84fdaf00b4876..9a0893ac43ef0 100644 --- a/NEWS +++ b/NEWS @@ -60,6 +60,9 @@ PHP NEWS . Fixed bug GH-15208 (Segfault with breakpoint map and phpdbg_clear()). (nielsdos) +- SAPI: + . Fixed bug GH-16998 (UBSAN warning in rfc1867). (nielsdos) + - SimpleXML: . Fixed bug GH-16808 (Segmentation fault in RecursiveIteratorIterator ->current() with a xml element input). (nielsdos) diff --git a/main/rfc1867.c b/main/rfc1867.c index 12794c414b342..fbfd6e78f9994 100644 --- a/main/rfc1867.c +++ b/main/rfc1867.c @@ -341,8 +341,8 @@ static char *next_line(multipart_buffer *self) } /* return entire buffer as a partial line */ line[self->bufsize] = 0; - self->buf_begin = ptr; self->bytes_in_buffer = 0; + /* Let fill_buffer() handle the reset of self->buf_begin */ } return line; diff --git a/tests/basic/gh16998.phpt b/tests/basic/gh16998.phpt new file mode 100644 index 0000000000000..8bfcbbda99dd0 --- /dev/null +++ b/tests/basic/gh16998.phpt @@ -0,0 +1,49 @@ +--TEST-- +GH-16998 (UBSAN warning in rfc1867) +--SKIPIF-- + +--FILE-- + '1', + 'CONTENT_TYPE' => "multipart/form-data; boundary=", + 'CONTENT_LENGTH' => strlen($body), + 'REQUEST_METHOD' => 'POST', + 'SCRIPT_FILENAME' => __DIR__ . '/GHSA-9pqp-7h25-4f32.inc', +]); +$spec = [ + 0 => ['pipe', 'r'], + 1 => STDOUT, + 2 => STDOUT, +]; +$pipes = []; +$handle = proc_open($cmd, $spec, $pipes, getcwd(), $env); +fwrite($pipes[0], $body); +proc_close($handle); +?> +--EXPECTF-- +X-Powered-By: PHP/%s +Content-type: text/html; charset=UTF-8 + +Hello world +array(0) { +} From 73ebc92617090fdd901592196ba708f0403a6002 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 27 Nov 2024 19:12:24 +0000 Subject: [PATCH 08/13] Fix GH-16959: snmpget modifies the `object_id` (as array). Instead of modifying the zval, we use the zend_try_get_string. close GH-16969 --- NEWS | 4 ++ ext/snmp/snmp.c | 80 +++++++++++++++++++++++++++---------- ext/snmp/tests/gh16959.phpt | 69 ++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 20 deletions(-) create mode 100644 ext/snmp/tests/gh16959.phpt diff --git a/NEWS b/NEWS index 9a0893ac43ef0..61c53db1378b5 100644 --- a/NEWS +++ b/NEWS @@ -67,6 +67,10 @@ PHP NEWS . Fixed bug GH-16808 (Segmentation fault in RecursiveIteratorIterator ->current() with a xml element input). (nielsdos) +- SNMP: + . Fixed bug GH-16959 (snmget modifies the object_id array). + (David Carlier) + - Standard: . Fixed bug GH-16905 (Internal iterator functions can't handle UNDEF properties). (nielsdos) diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c index 299d2d8fd08c8..dbf1aa553d88a 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -626,6 +626,31 @@ static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st, } /* }}} */ +static void php_snmp_zend_string_release_from_char_pointer(char *ptr) { + if (ptr) { + zend_string *pptr = (zend_string *)(ptr - XtOffsetOf(zend_string, val)); + zend_string_release(pptr); + } +} + +static void php_free_objid_query(struct objid_query *objid_query, HashTable* oid_ht, const HashTable *value_ht, int st) { + if (oid_ht) { + uint32_t count = zend_hash_num_elements(oid_ht); + + for (uint32_t i = 0; i < count; i ++) { + snmpobjarg *arg = &objid_query->vars[i]; + if (!arg->oid) { + break; + } + if (value_ht) { + php_snmp_zend_string_release_from_char_pointer(arg->value); + } + php_snmp_zend_string_release_from_char_pointer(arg->oid); + } + } + efree(objid_query->vars); +} + /* {{{ php_snmp_parse_oid * * OID parser (and type, value for SNMP_SET command) @@ -674,10 +699,15 @@ static bool php_snmp_parse_oid( return false; } objid_query->vars = (snmpobjarg *)safe_emalloc(sizeof(snmpobjarg), zend_hash_num_elements(oid_ht), 0); + memset(objid_query->vars, 0, sizeof(snmpobjarg) * zend_hash_num_elements(oid_ht)); objid_query->array_output = (st & SNMP_CMD_SET) == 0; ZEND_HASH_FOREACH_VAL(oid_ht, tmp_oid) { - convert_to_string(tmp_oid); - objid_query->vars[objid_query->count].oid = Z_STRVAL_P(tmp_oid); + zend_string *tmp = zval_try_get_string(tmp_oid); + if (!tmp) { + php_free_objid_query(objid_query, oid_ht, value_ht, st); + return false; + } + objid_query->vars[objid_query->count].oid = ZSTR_VAL(tmp); if (st & SNMP_CMD_SET) { if (type_str) { pptr = ZSTR_VAL(type_str); @@ -701,18 +731,24 @@ static bool php_snmp_parse_oid( } } if (idx_type < type_ht->nNumUsed) { - convert_to_string(tmp_type); - if (Z_STRLEN_P(tmp_type) != 1) { + zend_string *type = zval_try_get_string(tmp_type); + if (!type) { + php_free_objid_query(objid_query, oid_ht, value_ht, st); + return false; + } + size_t len = ZSTR_LEN(type); + char ptype = *ZSTR_VAL(type); + zend_string_release(type); + if (len != 1) { zend_value_error("Type must be a single character"); - efree(objid_query->vars); + php_free_objid_query(objid_query, oid_ht, value_ht, st); return false; } - pptr = Z_STRVAL_P(tmp_type); - objid_query->vars[objid_query->count].type = *pptr; + objid_query->vars[objid_query->count].type = ptype; idx_type++; } else { - php_error_docref(NULL, E_WARNING, "'%s': no type set", Z_STRVAL_P(tmp_oid)); - efree(objid_query->vars); + php_error_docref(NULL, E_WARNING, "'%s': no type set", ZSTR_VAL(tmp)); + php_free_objid_query(objid_query, oid_ht, value_ht, st); return false; } } @@ -738,12 +774,16 @@ static bool php_snmp_parse_oid( } } if (idx_value < value_ht->nNumUsed) { - convert_to_string(tmp_value); - objid_query->vars[objid_query->count].value = Z_STRVAL_P(tmp_value); + zend_string *tmp = zval_try_get_string(tmp_value); + if (!tmp) { + php_free_objid_query(objid_query, oid_ht, value_ht, st); + return false; + } + objid_query->vars[objid_query->count].value = ZSTR_VAL(tmp); idx_value++; } else { - php_error_docref(NULL, E_WARNING, "'%s': no value set", Z_STRVAL_P(tmp_oid)); - efree(objid_query->vars); + php_error_docref(NULL, E_WARNING, "'%s': no value set", ZSTR_VAL(tmp)); + php_free_objid_query(objid_query, oid_ht, value_ht, st); return false; } } @@ -756,14 +796,14 @@ static bool php_snmp_parse_oid( if (st & SNMP_CMD_WALK) { if (objid_query->count > 1) { php_snmp_error(object, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Multi OID walks are not supported!"); - efree(objid_query->vars); + php_free_objid_query(objid_query, oid_ht, value_ht, st); return false; } objid_query->vars[0].name_length = MAX_NAME_LEN; if (strlen(objid_query->vars[0].oid)) { /* on a walk, an empty string means top of tree - no error */ if (!snmp_parse_oid(objid_query->vars[0].oid, objid_query->vars[0].name, &(objid_query->vars[0].name_length))) { php_snmp_error(object, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Invalid object identifier: %s", objid_query->vars[0].oid); - efree(objid_query->vars); + php_free_objid_query(objid_query, oid_ht, value_ht, st); return false; } } else { @@ -775,7 +815,7 @@ static bool php_snmp_parse_oid( objid_query->vars[objid_query->offset].name_length = MAX_OID_LEN; if (!snmp_parse_oid(objid_query->vars[objid_query->offset].oid, objid_query->vars[objid_query->offset].name, &(objid_query->vars[objid_query->offset].name_length))) { php_snmp_error(object, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Invalid object identifier: %s", objid_query->vars[objid_query->offset].oid); - efree(objid_query->vars); + php_free_objid_query(objid_query, oid_ht, value_ht, st); return false; } } @@ -1252,12 +1292,12 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) if (session_less_mode) { if (!netsnmp_session_init(&session, version, a1, a2, timeout, retries)) { - efree(objid_query.vars); + php_free_objid_query(&objid_query, oid_ht, value_ht, st); netsnmp_session_free(&session); RETURN_FALSE; } if (version == SNMP_VERSION_3 && !netsnmp_session_set_security(session, a3, a4, a5, a6, a7, NULL, NULL)) { - efree(objid_query.vars); + php_free_objid_query(&objid_query, oid_ht, value_ht, st); netsnmp_session_free(&session); /* Warning message sent already, just bail out */ RETURN_FALSE; @@ -1268,7 +1308,7 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) session = snmp_object->session; if (!session) { zend_throw_error(NULL, "Invalid or uninitialized SNMP object"); - efree(objid_query.vars); + php_free_objid_query(&objid_query, oid_ht, value_ht, st); RETURN_THROWS(); } @@ -1294,7 +1334,7 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) php_snmp_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, st, session, &objid_query); - efree(objid_query.vars); + php_free_objid_query(&objid_query, oid_ht, value_ht, st); if (session_less_mode) { netsnmp_session_free(&session); diff --git a/ext/snmp/tests/gh16959.phpt b/ext/snmp/tests/gh16959.phpt new file mode 100644 index 0000000000000..ce647b15b9dac --- /dev/null +++ b/ext/snmp/tests/gh16959.phpt @@ -0,0 +1,69 @@ +--TEST-- +snmpget() modifies object_id array source +--EXTENSIONS-- +snmp +--SKIPIF-- + +--FILE-- + 077, -066 => -066, -0345 => -0345, 0 => 0 +); +var_dump($bad_object_ids); +var_dump(snmpget($hostname, "", $bad_object_ids) === false); +// The array should remain unmodified +var_dump($bad_object_ids); +try { + snmpget($hostname, "", [0 => new stdClass()]); +} catch (Throwable $e) { + echo $e->getMessage() . PHP_EOL; +} + +try { + snmp2_set($hostname, $communityWrite, $bad_object_ids, array(new stdClass()), array(null)); +} catch (Throwable $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + snmp2_set($hostname, $communityWrite, $bad_object_ids, array("toolongtype"), array(null)); +} catch (Throwable $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + snmp2_set($hostname, $communityWrite, $bad_object_ids, array(str_repeat("onetoomuch", random_int(1, 1))), array(null)); +} catch (Throwable $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +array(4) { + [63]=> + int(63) + [-54]=> + int(-54) + [-229]=> + int(-229) + [0]=> + int(0) +} + +Warning: snmpget(): Invalid object identifier: -54 in %s on line %d +bool(true) +array(4) { + [63]=> + int(63) + [-54]=> + int(-54) + [-229]=> + int(-229) + [0]=> + int(0) +} +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Type must be a single character +Type must be a single character From d7a37cc9ada85d2ae7d21e71dffd9bbd9c3b43b9 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 1 Dec 2024 15:18:44 +0100 Subject: [PATCH 09/13] Add missing backslash for TokenList interfaces in stub (#17009) Discovered while trying to generate class synopses. --- ext/dom/php_dom.stub.php | 2 +- ext/dom/php_dom_arginfo.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/dom/php_dom.stub.php b/ext/dom/php_dom.stub.php index f46550a012c0c..81713403e0e09 100644 --- a/ext/dom/php_dom.stub.php +++ b/ext/dom/php_dom.stub.php @@ -2096,7 +2096,7 @@ public function saveXmlFile(string $filename, int $options = 0): int|false {} * @not-serializable * @strict-properties */ - final class TokenList implements IteratorAggregate, Countable + final class TokenList implements \IteratorAggregate, \Countable { /** @implementation-alias Dom\Node::__construct */ private function __construct() {} diff --git a/ext/dom/php_dom_arginfo.h b/ext/dom/php_dom_arginfo.h index 1481c39bc1e03..ea42d6de49801 100644 --- a/ext/dom/php_dom_arginfo.h +++ b/ext/dom/php_dom_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 55ab8f866af63bd2edf96839d35bc8aba88e37ca */ + * Stub hash: d8a9d33a072c3c9e3798be5eee1833163a18f441 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_dom_import_simplexml, 0, 1, DOMAttr|DOMElement, 0) ZEND_ARG_TYPE_INFO(0, node, IS_OBJECT, 0) @@ -3525,13 +3525,13 @@ static zend_class_entry *register_class_Dom_XMLDocument(zend_class_entry *class_ return class_entry; } -static zend_class_entry *register_class_Dom_TokenList(zend_class_entry *class_entry_Dom_IteratorAggregate, zend_class_entry *class_entry_Dom_Countable) +static zend_class_entry *register_class_Dom_TokenList(zend_class_entry *class_entry_IteratorAggregate, zend_class_entry *class_entry_Countable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "Dom", "TokenList", class_Dom_TokenList_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); - zend_class_implements(class_entry, 2, class_entry_Dom_IteratorAggregate, class_entry_Dom_Countable); + zend_class_implements(class_entry, 2, class_entry_IteratorAggregate, class_entry_Countable); zval property_length_default_value; ZVAL_UNDEF(&property_length_default_value); From 1d2c544ccabefff831addbb5d40d63b317835b27 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 1 Dec 2024 18:55:38 +0100 Subject: [PATCH 10/13] Refactor disp_invokeex() to avoid superfluous recheck (GH-17001) Since we already know the method is callable, we can just call it directly. --- ext/com_dotnet/com_wrapper.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/ext/com_dotnet/com_wrapper.c b/ext/com_dotnet/com_wrapper.c index 81c31969161b8..6e885fa802e9f 100644 --- a/ext/com_dotnet/com_wrapper.c +++ b/ext/com_dotnet/com_wrapper.c @@ -256,31 +256,26 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex( /* TODO: if PHP raises an exception here, we should catch it * and expose it as a COM exception */ - + zend_fcall_info_cache fcc; if (wFlags & DISPATCH_PROPERTYPUT) { zend_update_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), ¶ms[0]); ret = S_OK; - } else if (wFlags & DISPATCH_METHOD && zend_is_callable_ex(name, Z_OBJ(disp->object), 0, NULL, NULL, NULL)) { + } else if (wFlags & DISPATCH_METHOD && zend_is_callable_ex(name, Z_OBJ(disp->object), 0, NULL, &fcc, NULL)) { zend_try { retval = &rv; - if (SUCCESS == call_user_function(NULL, &disp->object, name, - retval, pdp->cArgs, params)) { - ret = S_OK; - trace("function called ok\n"); - - /* Copy any modified values to callers copy of variant*/ - for (i = 0; i < pdp->cArgs; i++) { - php_com_dotnet_object *obj = CDNO_FETCH(¶ms[i]); - VARIANT *srcvar = &obj->v; - VARIANT *dstvar = &pdp->rgvarg[ pdp->cArgs - 1 - i]; - if ((V_VT(dstvar) & VT_BYREF) && obj->modified ) { - trace("percolate modified value for arg %u VT=%08x\n", i, V_VT(dstvar)); - php_com_copy_variant(dstvar, srcvar); - } + zend_call_known_fcc(&fcc, retval, pdp->cArgs, params, NULL); + ret = S_OK; + trace("function called ok\n"); + + /* Copy any modified values to callers copy of variant*/ + for (i = 0; i < pdp->cArgs; i++) { + php_com_dotnet_object *obj = CDNO_FETCH(¶ms[i]); + VARIANT *srcvar = &obj->v; + VARIANT *dstvar = &pdp->rgvarg[ pdp->cArgs - 1 - i]; + if ((V_VT(dstvar) & VT_BYREF) && obj->modified ) { + trace("percolate modified value for arg %u VT=%08x\n", i, V_VT(dstvar)); + php_com_copy_variant(dstvar, srcvar); } - } else { - trace("failed to call func\n"); - ret = DISP_E_EXCEPTION; } } zend_catch { trace("something blew up\n"); From 03bb112fb277f45abff861550a379dff2a56ea6d Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 2 Dec 2024 13:30:26 +0300 Subject: [PATCH 11/13] Fix GH-16984: function JIT overflow bug (#17015) --- ext/opcache/jit/zend_jit_ir.c | 4 +-- ext/opcache/tests/jit/gh16984.phpt | 41 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 ext/opcache/tests/jit/gh16984.phpt diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index e4b68d23520c8..beab53894a1b8 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -7204,9 +7204,9 @@ static int zend_jit_cmp(zend_jit_ctx *jit, while (n) { n--; - ir_IF_TRUE(end_inputs->refs[n]); + jit_IF_TRUE_FALSE_ex(jit, end_inputs->refs[n], label); ir_END_list(true_inputs); - ir_IF_FALSE(end_inputs->refs[n]); + jit_IF_TRUE_FALSE_ex(jit, end_inputs->refs[n], label2); ir_END_list(false_inputs); } ir_MERGE_list(true_inputs); diff --git a/ext/opcache/tests/jit/gh16984.phpt b/ext/opcache/tests/jit/gh16984.phpt new file mode 100644 index 0000000000000..8432959c41027 --- /dev/null +++ b/ext/opcache/tests/jit/gh16984.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-16984 (function JIT overflow bug) +--EXTENSIONS-- +opcache +--SKIPIF-- + +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=32M +opcache.jit=function +--FILE-- +foo($value); + if ($val <= PHP_INT_MAX) { + $test->integer = $val; + } +} + +function main() { + $test = new Test; + foo($test, 9223372036854775806); + foo($test, 9223372036854775807); // Also reproduces without this call, but this imitates the psalm code + var_dump($test->integer); +} + +main(); +?> +--EXPECT-- +int(9223372036854775807) From bc7902d99b45225c5dde4c123ae967871750314a Mon Sep 17 00:00:00 2001 From: hauk92 <47572039+hauk92@users.noreply.github.com> Date: Fri, 15 Nov 2024 15:22:26 +0100 Subject: [PATCH 12/13] Added mysqlnd.collect_memory_statistics to ini quick reference (#16819) Fixes #16818 Closes #16819 --- NEWS | 4 ++++ php.ini-development | 8 ++++++++ php.ini-production | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/NEWS b/NEWS index fb54b6c67a15d..1d9eaa59081fa 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,10 @@ PHP NEWS - Intl: . Bumped ICU requirement to ICU >= 57.1. (cmb) +- MySQLnd: + . Added mysqlnd.collect_memory_statistics to ini quick reference. + (hauk92) + - OPcache: . Fixed ZTS OPcache build on Cygwin. (cmb) . Added opcache.file_cache_read_only. (Samuel Melrose) diff --git a/php.ini-development b/php.ini-development index 31353facdb394..d739521a373d7 100644 --- a/php.ini-development +++ b/php.ini-development @@ -119,6 +119,11 @@ ; Development Value: 60 (60 seconds) ; Production Value: 60 (60 seconds) +; mysqlnd.collect_memory_statistics +; Default Value: Off +; Development Value: On +; Production Value: Off + ; output_buffering ; Default Value: Off ; Development Value: 4096 @@ -1193,6 +1198,9 @@ mysqlnd.collect_statistics = On ; Enable / Disable collection of memory usage statistics by mysqlnd which can be ; used to tune and monitor MySQL operations. +; Default Value: Off +; Development Value: On +; Production Value: Off mysqlnd.collect_memory_statistics = On ; Records communication from all extensions using mysqlnd to the specified log diff --git a/php.ini-production b/php.ini-production index e4fbd6e785f86..8e4afb683f9c1 100644 --- a/php.ini-production +++ b/php.ini-production @@ -119,6 +119,11 @@ ; Development Value: 60 (60 seconds) ; Production Value: 60 (60 seconds) +; mysqlnd.collect_memory_statistics +; Default Value: Off +; Development Value: On +; Production Value: Off + ; output_buffering ; Default Value: Off ; Development Value: 4096 @@ -1195,6 +1200,9 @@ mysqlnd.collect_statistics = On ; Enable / Disable collection of memory usage statistics by mysqlnd which can be ; used to tune and monitor MySQL operations. +; Default Value: Off +; Development Value: On +; Production Value: Off mysqlnd.collect_memory_statistics = Off ; Records communication from all extensions using mysqlnd to the specified log From c2d3734e899cd457d04f5d6ed93f467ec23fdd01 Mon Sep 17 00:00:00 2001 From: divinity76 Date: Sat, 21 Sep 2024 08:44:02 +0200 Subject: [PATCH 13/13] Fix GH-15964: printf() can strip sign of -INF We need to cater to negative infinity explicitly. Co-authored-by: Christoph M. Becker Closes GH-15965. --- NEWS | 1 + ext/standard/formatted_print.c | 7 ++++--- tests/strings/002.phpt | 4 ++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 675d7dfd37a30..e572109d26714 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,7 @@ PHP NEWS skipLazyInitialization() may change initialized proxy). (Arnaud) . Fix is_zend_ptr() huge block comparison. (nielsdos) . Fixed potential OOB read in zend_dirname() on Windows. (cmb) + . Fixed bug GH-15964 (printf() can strip sign of -INF). (divinity76, cmb) - Curl: . Fix various memory leaks in curl mime handling. (nielsdos) diff --git a/ext/standard/formatted_print.c b/ext/standard/formatted_print.c index ba0f73d9a9c22..8d8c09f443c04 100644 --- a/ext/standard/formatted_print.c +++ b/ext/standard/formatted_print.c @@ -246,9 +246,10 @@ php_sprintf_appenddouble(zend_string **buffer, size_t *pos, } if (zend_isinf(number)) { - is_negative = (number<0); - php_sprintf_appendstring(buffer, pos, "INF", 3, 0, padding, - alignment, 3, is_negative, 0, always_sign); + is_negative = (number<0); + char *str = is_negative ? "-INF" : "INF"; + php_sprintf_appendstring(buffer, pos, str, strlen(str), 0, padding, + alignment, strlen(str), is_negative, 0, always_sign); return; } diff --git a/tests/strings/002.phpt b/tests/strings/002.phpt index 54630836b1632..6284e9bf5d339 100644 --- a/tests/strings/002.phpt +++ b/tests/strings/002.phpt @@ -44,6 +44,8 @@ try { } catch(\ValueError $e) { print('Error found: '.$e->getMessage()."\n"); } +printf("printf test 31:%.17g\n", INF); +printf("printf test 32:%.17g\n", -INF); vprintf("vprintf test 1:%2\$-2d %1\$2d\n", array(1, 2)); @@ -83,4 +85,6 @@ printf test 27:3 1 2 printf test 28:02 1 printf test 29:2 1 printf test 30:Error found: Argument number specifier must be greater than zero and less than 2147483647 +printf test 31:INF +printf test 32:-INF vprintf test 1:2 1