diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index cae7a92178443..b3bff2c76171c 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -445,7 +445,7 @@ jobs: # Test causes a heap-buffer-overflow but I cannot reproduce it locally... php -r '$c = file_get_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php"); $c = str_replace("public function testSanitizeDeepNestedString()", "/** @group skip */\n public function testSanitizeDeepNestedString()", $c); file_put_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php", $c);' # Buggy FFI test in Symfony, see https://github.com/symfony/symfony/issues/47668 - php -r '$c = file_get_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php"); $c = str_replace("*/\n public function testCastNonTrailingCharPointer()", "* @group skip\n */\n public function testCastNonTrailingCharPointer()", $c); file_put_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php", $c);' + php -r '$c = file_get_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php"); $c = str_replace("public function testCastNonTrailingCharPointer()", "/** @group skip */\n public function testCastNonTrailingCharPointer()", $c); file_put_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php", $c);' export ASAN_OPTIONS=exitcode=139 export SYMFONY_DEPRECATIONS_HELPER=max[total]=999 X=0 diff --git a/NEWS b/NEWS index 8395fff08256b..5d1e07bf8eaf2 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,82 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.3.9 +01 Aug 2024, PHP 8.3.10 + +- Core: + . Fixed bug GH-13922 (Fixed support for systems with + sysconf(_SC_GETPW_R_SIZE_MAX) == -1). (Arnaud) + . Fixed bug GH-14626 (Fix is_zend_ptr() for huge blocks). (Arnaud) + . Fixed bug GH-14590 (Memory leak in FPM test gh13563-conf-bool-env.phpt. + (nielsdos) + . Fixed OSS-Fuzz #69765. (nielsdos) + . Fixed bug GH-14741 (Segmentation fault in Zend/zend_types.h). (nielsdos) + . Fixed bug GH-14969 (Use-after-free in property coercion with __toString()). + (ilutov) + +- Dom: + . Fixed bug GH-14702 (DOMDocument::xinclude() crash). (nielsdos) + +- Fileinfo: + . Fixed bug GH-14888 (README.REDIST.BINS refers to non-existing LICENSE). + (cmb) + +- Gd: + . ext/gd/tests/gh10614.phpt: skip if no PNG support. (orlitzky) + . restored warning instead of fata error. (dryabov) + +- LibXML: + . Fixed bug GH-14563 (Build failure with libxml2 v2.13.0). (nielsdos) + +- Opcache: + . Fixed bug GH-14550 (No warning message when Zend DTrace is enabled that + opcache.jit is implictly disabled). (nielsdos) + +- Output: + . Fixed bug GH-14808 (Unexpected null pointer in Zend/zend_string.h with + empty output buffer). (nielsdos) + +- PDO: + . Fixed bug GH-14712 (Crash with PDORow access to null property). + (David Carlier) + +- Phar: + . Fixed bug GH-14603 (null string from zip entry). + (David Carlier) + +- PHPDBG: + . Fixed bug GH-14596 (crashes with ASAN and ZEND_RC_DEBUG=1). + (David Carlier) + . Fixed bug GH-14553 (echo output trimmed at NULL byte). (nielsdos) + +- Shmop: + . Fixed bug GH-14537 (shmop Windows 11 crashes the process). (nielsdos) + +- SPL: + . Fixed bug GH-14639 (Member access within null pointer in + ext/spl/spl_observer.c). (nielsdos) + +- Standard: + . Fixed bug GH-14775 (range function overflow with negative step argument). + (David Carlier) + . Fix 32-bit wordwrap test failures. (orlitzky) + . Fixed bug GH-14774 (time_sleep_until overflow). (David Carlier) + +- Streams: + . Fixed bug GH-14930 (Custom stream wrapper dir_readdir output truncated to + 255 characters in PHP 8.3). (Joe Cai) + +- Tidy: + . Fix memory leak in tidy_repair_file(). (nielsdos) + +- Treewide: + . Fix compatibility with libxml2 2.13.2. (nielsdos) + +- XML: + . Move away from to-be-deprecated libxml fields. (nielsdos) + . Fixed bug GH-14834 (Error installing PHP when --with-pear is used). + (nielsdos) + +20 Jun 2024, PHP 8.3.9 - Core: . Fixed bug GH-14315 (Incompatible pointer type warnings). (Peter Kokot) @@ -15,7 +91,7 @@ PHP NEWS . Fixed bug GH-14549 (Incompatible function pointer type for fclose). (Ryan Carsten Schmidt) -- BCMatch: +- BCMath: . Fixed bug (bcpowmod() with mod = -1 returns 1 when it must be 0). (Girgias) - Curl: diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index dc8f9fefa3ab1..0af03b6ed8985 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -709,6 +709,7 @@ TSRM_API int shmget(key_t key, size_t size, int flags) CloseHandle(shm->segment); } UnmapViewOfFile(shm->descriptor); + shm->descriptor = NULL; return -1; } @@ -744,8 +745,8 @@ TSRM_API int shmdt(const void *shmaddr) shm->descriptor->shm_lpid = getpid(); shm->descriptor->shm_nattch--; - ret = 1; - if (!ret && shm->descriptor->shm_nattch <= 0) { + ret = 0; + if (shm->descriptor->shm_nattch <= 0) { ret = UnmapViewOfFile(shm->descriptor) ? 0 : -1; shm->descriptor = NULL; } diff --git a/Zend/tests/gh14626.phpt b/Zend/tests/gh14626.phpt new file mode 100644 index 0000000000000..c0c029fcd8474 --- /dev/null +++ b/Zend/tests/gh14626.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-14626: is_zend_ptr() may crash for non-zend ptrs when huge blocks exist +--EXTENSIONS-- +zend_test +--FILE-- + +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/tests/gh14969.phpt b/Zend/tests/gh14969.phpt new file mode 100644 index 0000000000000..dedbaa7456e00 --- /dev/null +++ b/Zend/tests/gh14969.phpt @@ -0,0 +1,47 @@ +--TEST-- +GH-14969: Crash on coercion with throwing __toString() +--FILE-- +prop = $c; +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} +var_dump($d); + +$c = new C(); +$d->prop = 'foo'; +try { + $d->prop = $c; +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} +var_dump($d); + +?> +--EXPECTF-- +C::__toString +object(D)#%d (0) { + ["prop"]=> + uninitialized(string) +} +C::__toString +object(D)#2 (1) { + ["prop"]=> + string(3) "foo" +} diff --git a/Zend/tests/oss-fuzz-69765.phpt b/Zend/tests/oss-fuzz-69765.phpt new file mode 100644 index 0000000000000..011b1ea525269 --- /dev/null +++ b/Zend/tests/oss-fuzz-69765.phpt @@ -0,0 +1,10 @@ +--TEST-- +OSS-Fuzz #69765: yield reference to nullsafe chain +--FILE-- +y?->y; +} +?> +--EXPECTF-- +Fatal error: Cannot take reference of a nullsafe chain in %s on line %d diff --git a/Zend/zend.h b/Zend/zend.h index 1727b91b19318..dbfd54c2c95e1 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.3.9-dev" +#define ZEND_VERSION "4.3.10" #define ZEND_ENGINE_3 diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index bf2116fc91f87..50f1bbbb69c01 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -2469,17 +2469,15 @@ ZEND_API bool is_zend_ptr(const void *ptr) } while (chunk != AG(mm_heap)->main_chunk); } - if (AG(mm_heap)->huge_list) { - zend_mm_huge_list *block = AG(mm_heap)->huge_list; - - do { - if (ptr >= (void*)block - && ptr < (void*)((char*)block + block->size)) { - return 1; - } - block = block->next; - } while (block != AG(mm_heap)->huge_list); + zend_mm_huge_list *block = AG(mm_heap)->huge_list; + while (block) { + if (ptr >= (void*)block + && ptr < (void*)((char*)block + block->size)) { + return 1; + } + block = block->next; } + return 0; } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 33c15f00b339c..9f04123d4a072 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2438,6 +2438,13 @@ static bool zend_ast_is_short_circuited(const zend_ast *ast) } } +static void zend_assert_not_short_circuited(const zend_ast *ast) +{ + if (zend_ast_is_short_circuited(ast)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot take reference of a nullsafe chain"); + } +} + /* Mark nodes that are an inner part of a short-circuiting chain. * We should not perform a "commit" on them, as it will be performed by the outer-most node. * We do this to avoid passing down an argument in various compile functions. */ @@ -3426,9 +3433,8 @@ static void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */ if (!zend_is_variable_or_call(expr_ast)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot assign reference to non referenceable value"); - } else if (zend_ast_is_short_circuited(expr_ast)) { - zend_error_noreturn(E_COMPILE_ERROR, - "Cannot take reference of a nullsafe chain"); + } else { + zend_assert_not_short_circuited(expr_ast); } zend_compile_var(&expr_node, expr_ast, BP_VAR_W, 1); @@ -3470,9 +3476,7 @@ static void zend_compile_assign_ref(znode *result, zend_ast *ast) /* {{{ */ zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); } zend_ensure_writable_variable(target_ast); - if (zend_ast_is_short_circuited(source_ast)) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot take reference of a nullsafe chain"); - } + zend_assert_not_short_circuited(source_ast); if (is_globals_fetch(source_ast)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot acquire reference to $GLOBALS"); } @@ -5173,10 +5177,7 @@ static void zend_compile_return(zend_ast *ast) /* {{{ */ expr_node.op_type = IS_CONST; ZVAL_NULL(&expr_node.u.constant); } else if (by_ref && zend_is_variable(expr_ast)) { - if (zend_ast_is_short_circuited(expr_ast)) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot take reference of a nullsafe chain"); - } - + zend_assert_not_short_circuited(expr_ast); zend_compile_var(&expr_node, expr_ast, BP_VAR_W, 1); } else { zend_compile_expr(&expr_node, expr_ast); @@ -9512,6 +9513,7 @@ static void zend_compile_yield(znode *result, zend_ast *ast) /* {{{ */ if (value_ast) { if (returns_by_ref && zend_is_variable(value_ast)) { + zend_assert_not_short_circuited(value_ast); zend_compile_var(&value_node, value_ast, BP_VAR_W, 1); } else { zend_compile_expr(&value_node, value_ast); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 555e250bbca71..8da2d37a25aad 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -3234,6 +3234,9 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c } } + /* Pointer on property callback is required */ + ZEND_ASSERT(zobj->handlers->get_property_ptr_ptr != NULL); + if (prop_op_type == IS_CONST) { name = Z_STR_P(prop_ptr); } else { diff --git a/Zend/zend_ini_parser.y b/Zend/zend_ini_parser.y index 071fdeb13fb75..352f2eb3eec26 100644 --- a/Zend/zend_ini_parser.y +++ b/Zend/zend_ini_parser.y @@ -179,8 +179,10 @@ static void zend_ini_get_var(zval *result, zval *name, zval *fallback) if ((curval = zend_get_configuration_directive(Z_STR_P(name))) != NULL) { ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(curval), Z_STRLEN_P(curval), ZEND_SYSTEM_INI)); /* ..or if not found, try ENV */ - } else if ((envvar = zend_getenv(Z_STRVAL_P(name), Z_STRLEN_P(name))) != NULL || - (envvar = getenv(Z_STRVAL_P(name))) != NULL) { + } else if ((envvar = zend_getenv(Z_STRVAL_P(name), Z_STRLEN_P(name))) != NULL) { + ZVAL_NEW_STR(result, zend_string_init(envvar, strlen(envvar), ZEND_SYSTEM_INI)); + efree(envvar); + } else if ((envvar = getenv(Z_STRVAL_P(name))) != NULL) { ZVAL_NEW_STR(result, zend_string_init(envvar, strlen(envvar), ZEND_SYSTEM_INI)); /* ..or if not defined, try fallback value */ } else if (fallback) { diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index 5148668d945c7..caa96f9cf5e56 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -667,6 +667,7 @@ ZEND_API void zend_register_interfaces(void) memcpy(&zend_internal_iterator_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + zend_internal_iterator_handlers.clone_obj = NULL; zend_internal_iterator_handlers.free_obj = zend_internal_iterator_free; } /* }}} */ diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 3aba713616bdb..2e5ac32590058 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -846,7 +846,7 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva goto exit; } if (UNEXPECTED(!type_matched)) { - Z_TRY_DELREF_P(value); + zval_ptr_dtor(&tmp); variable_ptr = &EG(error_zval); goto exit; } @@ -949,7 +949,7 @@ found:; goto exit; } if (UNEXPECTED(!type_matched)) { - zval_ptr_dtor(value); + zval_ptr_dtor(&tmp); goto exit; } value = &tmp; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f731653a24813..2c604d9724971 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8024,7 +8024,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) /* Exception was thrown before executing any op */ if (UNEXPECTED(!throw_op)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, -1, 0, 0); + ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, -1, op_num, 0); } uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes; diff --git a/configure.ac b/configure.ac index 6a23c1424ebca..8599086e1ddda 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.3.9-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.3.10],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/ext/curl/tests/curl_basic_008.phpt b/ext/curl/tests/curl_basic_008.phpt index cd4496528ceeb..353c44327c5e8 100644 --- a/ext/curl/tests/curl_basic_008.phpt +++ b/ext/curl/tests/curl_basic_008.phpt @@ -6,7 +6,7 @@ TestFest 2009 - AFUP - Perrick Penet curl --SKIPIF-- string(17) "Content String 10" @@ -122,5 +122,5 @@ array(6) { } === RUNNING WITH NO LOCK === -Warning: dba_open(): Locking cannot be disabled for handler ndbm in /home/girgias/Dev/php-src/ext/dba/tests/setup/setup_dba_tests.inc on line 40 +Warning: dba_open(): Locking cannot be disabled for handler ndbm in %s on line %d Failed to create DB diff --git a/ext/dom/document.c b/ext/dom/document.c index 588aabda3976e..ee9c0d4d5ff31 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -1336,11 +1336,13 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so if (keep_blanks == 0 && ! (options & XML_PARSE_NOBLANKS)) { options |= XML_PARSE_NOBLANKS; } + if (recover) { + options |= XML_PARSE_RECOVER; + } php_libxml_sanitize_parse_ctxt_options(ctxt); xmlCtxtUseOptions(ctxt, options); - ctxt->recovery = recover; if (recover) { old_error_reporting = EG(error_reporting); EG(error_reporting) = old_error_reporting | E_WARNING; @@ -1350,7 +1352,7 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so if (ctxt->wellFormed || recover) { ret = ctxt->myDoc; - if (ctxt->recovery) { + if (recover) { EG(error_reporting) = old_error_reporting; } /* If loading from memory, set the base reference uri for the document */ @@ -1625,6 +1627,58 @@ static void php_dom_remove_xinclude_nodes(xmlNodePtr cur) /* {{{ */ } /* }}} */ +/* Backported from master branch xml_common.h */ +static zend_always_inline xmlNodePtr php_dom_next_in_tree_order(const xmlNode *nodep, const xmlNode *basep) +{ + if (nodep->type == XML_ELEMENT_NODE && nodep->children) { + return nodep->children; + } + + if (nodep->next) { + return nodep->next; + } else { + /* Go upwards, until we find a parent node with a next sibling, or until we hit the base. */ + do { + nodep = nodep->parent; + if (nodep == basep) { + return NULL; + } + } while (nodep->next == NULL); + return nodep->next; + } +} + +static void dom_xinclude_strip_references(xmlNodePtr basep) +{ + php_libxml_node_free_resource(basep); + + xmlNodePtr current = basep->children; + + while (current) { + php_libxml_node_free_resource(current); + current = php_dom_next_in_tree_order(current, basep); + } +} + +/* See GH-14702. + * We have to remove userland references to xinclude fallback nodes because libxml2 will make clones of these + * and remove the original nodes. If the originals are removed while there are still userland references + * this will cause memory corruption. */ +static void dom_xinclude_strip_fallback_references(const xmlNode *basep) +{ + xmlNodePtr current = basep->children; + + while (current) { + if (current->type == XML_ELEMENT_NODE && current->ns != NULL && current->_private != NULL + && xmlStrEqual(current->name, XINCLUDE_FALLBACK) + && (xmlStrEqual(current->ns->href, XINCLUDE_NS) || xmlStrEqual(current->ns->href, XINCLUDE_OLD_NS))) { + dom_xinclude_strip_references(current); + } + + current = php_dom_next_in_tree_order(current, basep); + } +} + /* {{{ Substitutues xincludes in a DomDocument */ PHP_METHOD(DOMDocument, xinclude) { @@ -1647,6 +1701,8 @@ PHP_METHOD(DOMDocument, xinclude) DOM_GET_OBJ(docp, id, xmlDocPtr, intern); + dom_xinclude_strip_fallback_references((const xmlNode *) docp); + PHP_LIBXML_SANITIZE_GLOBALS(xinclude); err = xmlXIncludeProcessFlags(docp, (int)flags); PHP_LIBXML_RESTORE_GLOBALS(xinclude); diff --git a/ext/dom/tests/DOMDocument_loadHTMLfile_error1.phpt b/ext/dom/tests/DOMDocument_loadHTMLfile_error1.phpt index 08bf361216fb6..dabf396eaea00 100644 --- a/ext/dom/tests/DOMDocument_loadHTMLfile_error1.phpt +++ b/ext/dom/tests/DOMDocument_loadHTMLfile_error1.phpt @@ -13,4 +13,4 @@ $result = $doc->loadHTMLFile(__DIR__ . "/ffff/test.html"); assert($result === false); ?> --EXPECTF-- -%r(PHP ){0,1}%rWarning: DOMDocument::loadHTMLFile(): I/O warning : failed to load external entity %s +%r(PHP ){0,1}%rWarning: DOMDocument::loadHTMLFile(): I/O %s diff --git a/ext/dom/tests/DOMDocument_loadXML_error2_gte2_12.phpt b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_12.phpt index 6a3ff5841f565..d84d690c715fb 100644 --- a/ext/dom/tests/DOMDocument_loadXML_error2_gte2_12.phpt +++ b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_12.phpt @@ -23,7 +23,7 @@ domdocumentloadxml_test_method.inc --EXPECTF-- Warning: DOMDocument::loadXML(): AttValue: " or ' expected in Entity, line: 4 in %s on line %d -Warning: DOMDocument::loadXML(): internal error: xmlParseStartTag: problem parsing attributes in Entity, line: 4 in %s on line %d +Warning: DOMDocument::loadXML():%sattributes%s Warning: DOMDocument::loadXML(): Couldn't find end of Start Tag book line 4 in Entity, line: 4 in %s on line %d diff --git a/ext/dom/tests/DOMDocument_load_error2_gte2_12.phpt b/ext/dom/tests/DOMDocument_load_error2_gte2_12.phpt index 4fadf41736124..aaab30ed64573 100644 --- a/ext/dom/tests/DOMDocument_load_error2_gte2_12.phpt +++ b/ext/dom/tests/DOMDocument_load_error2_gte2_12.phpt @@ -23,7 +23,7 @@ domdocumentload_test_method.inc --EXPECTF-- Warning: DOMDocument::load(): AttValue: " or ' expected in %s on line %d -Warning: DOMDocument::load(): internal error: xmlParseStartTag: problem parsing attributes in %s on line %d +Warning: DOMDocument::load():%sattributes%s Warning: DOMDocument::load(): Couldn't find end of Start Tag book line 4 in %s on line %d diff --git a/ext/dom/tests/DOMDocument_relaxNGValidate_error2.phpt b/ext/dom/tests/DOMDocument_relaxNGValidate_error2.phpt index 1ad46e014a0a7..cb506f70789d8 100644 --- a/ext/dom/tests/DOMDocument_relaxNGValidate_error2.phpt +++ b/ext/dom/tests/DOMDocument_relaxNGValidate_error2.phpt @@ -20,7 +20,7 @@ $result = $doc->relaxNGValidate($rng); var_dump($result); ?> --EXPECTF-- -Warning: DOMDocument::relaxNGValidate(): I/O warning : failed to load external entity "%s/foo.rng" in %s on line %d +Warning: DOMDocument::relaxNGValidate(): I/O %s : failed to load %s Warning: DOMDocument::relaxNGValidate(): xmlRelaxNGParse: could not load %s/foo.rng in %s on line %d diff --git a/ext/dom/tests/DOMDocument_saveHTMLFile_basic.phpt b/ext/dom/tests/DOMDocument_saveHTMLFile_basic.phpt index cf392c0262fd4..32f1a3c36e2f4 100644 --- a/ext/dom/tests/DOMDocument_saveHTMLFile_basic.phpt +++ b/ext/dom/tests/DOMDocument_saveHTMLFile_basic.phpt @@ -5,6 +5,10 @@ Knut Urdalen #PHPTestFest2009 Norway 2009-06-09 \o/ --EXTENSIONS-- dom +--SKIPIF-- += 21300) die("skip see https://gitlab.gnome.org/GNOME/libxml2/-/issues/756"); +?> --FILE-- #PHPTestFest2009 Norway 2009-06-09 \o/ --EXTENSIONS-- dom +--SKIPIF-- += 21300) die("skip see https://gitlab.gnome.org/GNOME/libxml2/-/issues/756"); +?> --FILE-- +#PHPTestFest2009 Norway 2009-06-09 \o/ +--EXTENSIONS-- +dom +--SKIPIF-- + +--FILE-- +formatOutput = true; +$root = $doc->createElement('html'); +$root = $doc->appendChild($root); +$head = $doc->createElement('head'); +$head = $root->appendChild($head); +$title = $doc->createElement('title'); +$title = $head->appendChild($title); +$text = $doc->createTextNode('This is the title'); +$text = $title->appendChild($text); +$bytes = $doc->saveHTMLFile($filename); +var_dump($bytes); +echo file_get_contents($filename); +unlink($filename); +?> +--EXPECT-- +int(59) +This is the title diff --git a/ext/dom/tests/DOMDocument_saveHTML_basic_gte_2_13.phpt b/ext/dom/tests/DOMDocument_saveHTML_basic_gte_2_13.phpt new file mode 100644 index 0000000000000..c0be105253dd7 --- /dev/null +++ b/ext/dom/tests/DOMDocument_saveHTML_basic_gte_2_13.phpt @@ -0,0 +1,31 @@ +--TEST-- +DOMDocument::saveHTMLFile() should dump the internal document into a file using HTML formatting +--CREDITS-- +Knut Urdalen +#PHPTestFest2009 Norway 2009-06-09 \o/ +--EXTENSIONS-- +dom +--SKIPIF-- + +--FILE-- +createElement('html'); +$root = $doc->appendChild($root); +$head = $doc->createElement('head'); +$head = $root->appendChild($head); +$title = $doc->createElement('title'); +$title = $head->appendChild($title); +$text = $doc->createTextNode('This is the title'); +$text = $title->appendChild($text); +$bytes = $doc->saveHTMLFile($filename); +var_dump($bytes); +echo file_get_contents($filename); +unlink($filename); +?> +--EXPECT-- +int(59) +This is the title diff --git a/ext/dom/tests/DOMDocument_schemaValidate_error5.phpt b/ext/dom/tests/DOMDocument_schemaValidate_error5.phpt index 2feda5d1e1f8d..bc94abacf22ad 100644 --- a/ext/dom/tests/DOMDocument_schemaValidate_error5.phpt +++ b/ext/dom/tests/DOMDocument_schemaValidate_error5.phpt @@ -17,7 +17,7 @@ var_dump($result); ?> --EXPECTF-- -Warning: DOMDocument::schemaValidate(): I/O warning : failed to load external entity "%snon-existent-file" in %s.php on line %d +Warning: DOMDocument::schemaValidate(): I/O %s : failed to load %s Warning: DOMDocument::schemaValidate(): Failed to locate the main schema resource at '%s/non-existent-file'. in %s.php on line %d diff --git a/ext/dom/tests/DOMElement_insertAdjacentText.phpt b/ext/dom/tests/DOMElement_insertAdjacentText.phpt index 58af0812d6fe5..305e8c752535b 100644 --- a/ext/dom/tests/DOMElement_insertAdjacentText.phpt +++ b/ext/dom/tests/DOMElement_insertAdjacentText.phpt @@ -51,7 +51,6 @@ echo $dom->saveXML($empty), "\n"; $AText = $empty->firstChild; $empty->insertAdjacentText("afterbegin", 'B'); echo $dom->saveXML($empty), "\n"; -var_dump($AText->textContent); ?> --EXPECT-- @@ -78,4 +77,3 @@ Syntax Error --- Normal cases starting from empty element --- A BA -string(2) "BA" diff --git a/ext/dom/tests/DOMEntityReference_predefined_free.phpt b/ext/dom/tests/DOMEntityReference_predefined_free.phpt index 4b971d83703ed..46e54e1b7d308 100644 --- a/ext/dom/tests/DOMEntityReference_predefined_free.phpt +++ b/ext/dom/tests/DOMEntityReference_predefined_free.phpt @@ -7,7 +7,7 @@ dom $ref = new DOMEntityReference("amp"); var_dump($ref); ?> ---EXPECT-- +--EXPECTF-- object(DOMEntityReference)#1 (17) { ["nodeName"]=> string(3) "amp" @@ -42,5 +42,5 @@ object(DOMEntityReference)#1 (17) { ["baseURI"]=> NULL ["textContent"]=> - string(0) "" + string(%d) "%S" } diff --git a/ext/dom/tests/dom_create_element.phpt b/ext/dom/tests/dom_create_element.phpt index 82d73826da433..19acb5614d575 100644 --- a/ext/dom/tests/dom_create_element.phpt +++ b/ext/dom/tests/dom_create_element.phpt @@ -251,14 +251,10 @@ try { print $e->getMessage() . "\n"; } -/* This isn't because the xml namespace isn't there and we can't create it */ -print "29 DOMElement::__construct('xml:valid', '', 'http://www.w3.org/XML/1998/namespace')\n"; -try { - $element = new DomElement('xml:valid', '', 'http://www.w3.org/XML/1998/namespace'); - print "valid\n"; -} catch (Exception $e) { - print $e->getMessage() . "\n"; -} +/* There used to be a 29 here that tested DOMElement::__construct('xml:valid', '', 'http://www.w3.org/XML/1998/namespace'). + * In libxml2 version 2.12 or prior this didn't work because the xml namespace isn't there and you can't create it without + * a document. Starting from libxml2 version 2.13 it does actually work because the XML namespace is statically defined. + * The behaviour from version 2.13 is actually the desired behaviour anyway. */ /* the qualifiedName or its prefix is "xmlns" and the namespaceURI is @@ -378,8 +374,6 @@ Namespace Error Namespace Error 28 DOMDocument::createElementNS('http://www.w3.org/XML/1998/namespace', 'xml:valid') valid -29 DOMElement::__construct('xml:valid', '', 'http://www.w3.org/XML/1998/namespace') -Namespace Error 30 DOMDocument::createElementNS('http://wrong.namespaceuri.com/', 'xmlns:valid') Namespace Error 31 DOMElement::__construct('xmlns:valid', '', 'http://wrong.namespaceuri.com/') diff --git a/ext/dom/tests/gh14702.phpt b/ext/dom/tests/gh14702.phpt new file mode 100644 index 0000000000000..9811bb7883acb --- /dev/null +++ b/ext/dom/tests/gh14702.phpt @@ -0,0 +1,66 @@ +--TEST-- +GH-14702 (DOMDocument::xinclude() crash) +--EXTENSIONS-- +dom +--FILE-- +loadXML(<< + + + + + + + +XML); +$xi = $doc->createElementNS('http://www.w3.org/2001/XInclude', 'xi:include'); +$xi->setAttribute('href', 'nonexistent'); + +$fallback = $doc->createElementNS('http://www.w3.org/2001/XInclude', 'xi:fallback'); +$xi->appendChild($fallback); +$child1 = $fallback->appendChild($doc->createElement('fallback-child1')); +$child2 = $fallback->appendChild($doc->createElement('fallback-child2')); + +$xpath = new DOMXPath($doc); +$toReplace = $xpath->query('//child')->item(0); +$toReplace->parentNode->replaceChild($xi, $toReplace); + +$keep = $doc->documentElement->lastElementChild; + +var_dump(@$doc->xinclude()); +echo $doc->saveXML(); + +var_dump($child1, $child2, $fallback, $keep->nodeName); + +$keep->textContent = 'still works'; +echo $doc->saveXML(); +?> +--EXPECT-- +int(2) + + + + + + +object(DOMElement)#4 (1) { + ["schemaTypeInfo"]=> + NULL +} +object(DOMElement)#5 (1) { + ["schemaTypeInfo"]=> + NULL +} +object(DOMElement)#3 (1) { + ["schemaTypeInfo"]=> + NULL +} +string(4) "keep" + + + + + still works + diff --git a/ext/ffi/tests/gh14626.phpt b/ext/ffi/tests/gh14626.phpt new file mode 100644 index 0000000000000..f69122e288917 --- /dev/null +++ b/ext/ffi/tests/gh14626.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-14626: FFI::free() may crash in is_zend_ptr() when at least one huge block exists and the ptr is non-zend +--EXTENSIONS-- +ffi +--SKIPIF-- + +--INI-- +ffi.enable=1 +--FILE-- +malloc(10); +$addr = $ffi->cast("uintptr_t", $ffi->cast("char*", $ptr))->cdata; + +$ptr = FFI::cdef()->cast("char*", $addr); + +// Should not crash in is_zend_ptr() +FFI::free($ptr); + +?> +==DONE== +--EXPECT-- +==DONE== diff --git a/ext/fileinfo/libmagic/LICENSE b/ext/fileinfo/libmagic/LICENSE new file mode 100644 index 0000000000000..16410a17f2f5b --- /dev/null +++ b/ext/fileinfo/libmagic/LICENSE @@ -0,0 +1,29 @@ +$File: COPYING,v 1.2 2018/09/09 20:33:28 christos Exp $ +Copyright (c) Ian F. Darwin 1986, 1987, 1989, 1990, 1991, 1992, 1994, 1995. +Software written by Ian F. Darwin and others; +maintained 1994- Christos Zoulas. + +This software is not subject to any export provision of the United States +Department of Commerce, and may be exported to any country or planet. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice immediately at the beginning of the file, without modification, + this list of conditions, and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/ext/gd/libgd/gd_webp.c b/ext/gd/libgd/gd_webp.c index a0d8a0cf49f5c..4e270db150179 100644 --- a/ext/gd/libgd/gd_webp.c +++ b/ext/gd/libgd/gd_webp.c @@ -3,6 +3,7 @@ #include #include #include "gd.h" +#include "gd_errors.h" #include "gdhelpers.h" #ifdef HAVE_LIBWEBP @@ -56,7 +57,7 @@ gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile) if (filedata) { gdFree(filedata); } - zend_error(E_ERROR, "WebP decode: realloc failed"); + gd_error("WebP decode: realloc failed"); return NULL; } @@ -67,7 +68,7 @@ gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile) } while (n>0 && n!=EOF); if (WebPGetInfo(filedata,size, &width, &height) == 0) { - zend_error(E_ERROR, "gd-webp cannot get webp info"); + gd_error("gd-webp cannot get webp info"); gdFree(filedata); return NULL; } @@ -79,7 +80,7 @@ gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile) } argb = WebPDecodeARGB(filedata, size, &width, &height); if (!argb) { - zend_error(E_ERROR, "gd-webp cannot allocate temporary buffer"); + gd_error("gd-webp cannot allocate temporary buffer"); gdFree(filedata); gdImageDestroy(im); return NULL; @@ -113,7 +114,7 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality) } if (!gdImageTrueColor(im)) { - zend_error(E_ERROR, "Palette image not supported by webp"); + gd_error("Palette image not supported by webp"); return; } @@ -159,7 +160,7 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality) } if (out_size == 0) { - zend_error(E_ERROR, "gd-webp encoding failed"); + gd_error("gd-webp encoding failed"); goto freeargb; } gdPutBuf(out, out_size, outfile); diff --git a/ext/gd/tests/gh10614.phpt b/ext/gd/tests/gh10614.phpt index c0689141837cd..1b91115d748d2 100644 --- a/ext/gd/tests/gh10614.phpt +++ b/ext/gd/tests/gh10614.phpt @@ -5,6 +5,9 @@ gd --SKIPIF-- =')) die("skip test requires GD 2.3.4 or older"); +if (!(imagetypes() & IMG_PNG)) { + die("skip No PNG support"); +} ?> --FILE-- + --FILE-- +--FILE-- + +--CLEAN-- + +--EXPECTF-- +Warning: imagecreatefromwebp(): gd-webp cannot get webp info in %s on line %d + +Warning: imagecreatefromwebp(): "%s" is not a valid WEBP file in %s on line %d +bool(false) diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 299dd1e11de5f..0c252e5e455aa 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -580,8 +580,10 @@ php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc) static xmlOutputBufferPtr php_libxml_output_buffer_create_filename(const char *URI, xmlCharEncodingHandlerPtr encoder, - int compression ATTRIBUTE_UNUSED) + int compression) { + ZEND_IGNORE_VALUE(compression); + xmlOutputBufferPtr ret; xmlURIPtr puri; void *context = NULL; diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h index 9fbe9ff0f9e81..06201139673dc 100644 --- a/ext/libxml/php_libxml.h +++ b/ext/libxml/php_libxml.h @@ -197,6 +197,7 @@ ZEND_TSRMLS_CACHE_EXTERN() * Generally faster because no locking is involved, and this has the advantage that it sets the options to a known good value. */ static zend_always_inline void php_libxml_sanitize_parse_ctxt_options(xmlParserCtxtPtr ctxt) { + PHP_LIBXML_IGNORE_DEPRECATIONS_START ctxt->loadsubset = 0; ctxt->validate = 0; ctxt->pedantic = 0; @@ -204,6 +205,7 @@ static zend_always_inline void php_libxml_sanitize_parse_ctxt_options(xmlParserC ctxt->linenumbers = 0; ctxt->keepBlanks = 1; ctxt->options = 0; + PHP_LIBXML_IGNORE_DEPRECATIONS_END } #else /* HAVE_LIBXML */ diff --git a/ext/libxml/php_libxml2.def b/ext/libxml/php_libxml2.def index 5980df8bf8891..06c05f188e8fb 100644 --- a/ext/libxml/php_libxml2.def +++ b/ext/libxml/php_libxml2.def @@ -345,7 +345,6 @@ xmlElemDump xmlEncodeEntities xmlEncodeEntitiesReentrant xmlEncodeSpecialChars -xmlErrMemory xmlFileClose xmlFileMatch xmlFileOpen diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index aba71473583d0..e700e056a8554 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -4895,7 +4895,9 @@ ZEND_EXT_API int zend_jit_check_support(void) } if (zend_execute_ex != execute_ex) { - if (strcmp(sapi_module.name, "phpdbg") != 0) { + if (zend_dtrace_enabled) { + zend_error(E_WARNING, "JIT is incompatible with DTrace. JIT disabled."); + } else if (strcmp(sapi_module.name, "phpdbg") != 0) { zend_error(E_WARNING, "JIT is incompatible with third party extensions that override zend_execute_ex(). JIT disabled."); } JIT_G(enabled) = 0; diff --git a/ext/openssl/tests/gh13860.phpt b/ext/openssl/tests/gh13860.phpt index 0b52e0e0583ab..aff0df15cca95 100644 --- a/ext/openssl/tests/gh13860.phpt +++ b/ext/openssl/tests/gh13860.phpt @@ -18,8 +18,8 @@ $serverCode = <<<'CODE' $client = @stream_socket_accept($server); if ($client) { - fwrite($client, "xx"); phpt_wait(); + fwrite($client, "xx"); fclose($client); phpt_notify(); } diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 301dd2eea224d..a1a16b0c834b9 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -2450,6 +2450,16 @@ static zend_function *row_get_ctor(zend_object *object) return NULL; } +static zval *pdo_row_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot) +{ + ZEND_IGNORE_VALUE(object); + ZEND_IGNORE_VALUE(name); + ZEND_IGNORE_VALUE(type); + ZEND_IGNORE_VALUE(cache_slot); + + return NULL; +} + void pdo_row_free_storage(zend_object *std) { pdo_row_t *row = (pdo_row_t *)std; @@ -2490,7 +2500,7 @@ void pdo_stmt_init(void) memcpy(&pdo_row_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); pdo_row_object_handlers.free_obj = pdo_row_free_storage; pdo_row_object_handlers.clone_obj = NULL; - pdo_row_object_handlers.get_property_ptr_ptr = NULL; + pdo_row_object_handlers.get_property_ptr_ptr = pdo_row_get_property_ptr_ptr; pdo_row_object_handlers.read_property = row_prop_read; pdo_row_object_handlers.write_property = row_prop_write; pdo_row_object_handlers.has_property = row_prop_exists; diff --git a/ext/pdo_sqlite/tests/gh14712.phpt b/ext/pdo_sqlite/tests/gh14712.phpt new file mode 100644 index 0000000000000..d565abacdcd11 --- /dev/null +++ b/ext/pdo_sqlite/tests/gh14712.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-14712: segfault on PDORow +--EXTENSIONS-- +pdo_sqlite +--CREDITS-- +YuanchengJiang +--FILE-- +query("select 1 as queryStringxx")->fetch(PDO::FETCH_LAZY)->documentElement->firstChild->nextElementSibling->textContent = "é"; +} catch (Error $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Attempt to modify property "firstChild" on null diff --git a/ext/phar/tests/gh14603.phpt b/ext/phar/tests/gh14603.phpt new file mode 100644 index 0000000000000..95b9fa30fd559 Binary files /dev/null and b/ext/phar/tests/gh14603.phpt differ diff --git a/ext/phar/zip.c b/ext/phar/zip.c index a7b4678660843..c1f7d47c761cf 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -770,7 +770,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alia } } - zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), actual_alias, mydata->alias_len, mydata); + zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, mydata); mydata->alias = pestrndup(alias, alias_len, mydata->is_persistent); mydata->alias_len = alias_len; } else { diff --git a/ext/shmop/tests/gh14537.phpt b/ext/shmop/tests/gh14537.phpt new file mode 100644 index 0000000000000..05af26a70ffa9 --- /dev/null +++ b/ext/shmop/tests/gh14537.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-14537: shmop Windows 11 crashes the process +--EXTENSIONS-- +shmop +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +object(Shmop)#1 (0) { +} + +Warning: shmop_open(): Unable to attach or create shared memory segment "No error" in %s on line %d +bool(false) diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index eebf4af023955..1047fb4f19cb2 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -1493,6 +1493,35 @@ static void sxe_add_namespaces(php_sxe_object *sxe, xmlNodePtr node, bool recurs } } /* }}} */ +static inline void sxe_object_free_iterxpath(php_sxe_object *sxe) +{ + if (!Z_ISUNDEF(sxe->iter.data)) { + zval_ptr_dtor(&sxe->iter.data); + ZVAL_UNDEF(&sxe->iter.data); + } + + if (sxe->iter.name) { + efree(sxe->iter.name); + sxe->iter.name = NULL; + } + if (sxe->iter.nsprefix) { + efree(sxe->iter.nsprefix); + sxe->iter.nsprefix = NULL; + } + if (!Z_ISUNDEF(sxe->tmp)) { + zval_ptr_dtor(&sxe->tmp); + ZVAL_UNDEF(&sxe->tmp); + } + + php_libxml_node_decrement_resource((php_libxml_node_object *)sxe); + + if (sxe->xpath) { + xmlXPathFreeContext(sxe->xpath); + sxe->xpath = NULL; + } +} + + /* {{{ Return all namespaces in use */ PHP_METHOD(SimpleXMLElement, getNamespaces) { @@ -2149,29 +2178,7 @@ static void sxe_object_free_storage(zend_object *object) zend_object_std_dtor(&sxe->zo); - if (!Z_ISUNDEF(sxe->iter.data)) { - zval_ptr_dtor(&sxe->iter.data); - ZVAL_UNDEF(&sxe->iter.data); - } - - if (sxe->iter.name) { - efree(sxe->iter.name); - sxe->iter.name = NULL; - } - if (sxe->iter.nsprefix) { - efree(sxe->iter.nsprefix); - sxe->iter.nsprefix = NULL; - } - if (!Z_ISUNDEF(sxe->tmp)) { - zval_ptr_dtor(&sxe->tmp); - ZVAL_UNDEF(&sxe->tmp); - } - - php_libxml_node_decrement_resource((php_libxml_node_object *)sxe); - - if (sxe->xpath) { - xmlXPathFreeContext(sxe->xpath); - } + sxe_object_free_iterxpath(sxe); if (sxe->properties) { zend_hash_destroy(sxe->properties); @@ -2371,11 +2378,12 @@ PHP_METHOD(SimpleXMLElement, __construct) PHP_LIBXML_RESTORE_GLOBALS(read_file_or_memory); if (!docp) { - ((php_libxml_node_object *)sxe)->document = NULL; zend_throw_exception(zend_ce_exception, "String could not be parsed as XML", 0); RETURN_THROWS(); } + sxe_object_free_iterxpath(sxe); + sxe->iter.nsprefix = ns_len ? (xmlChar*)estrdup(ns) : NULL; sxe->iter.isprefix = isprefix; php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp); diff --git a/ext/simplexml/tests/bug79971_1.phpt b/ext/simplexml/tests/bug79971_1.phpt index 2ee07c81822ff..df38ddf20e847 100644 --- a/ext/simplexml/tests/bug79971_1.phpt +++ b/ext/simplexml/tests/bug79971_1.phpt @@ -22,7 +22,7 @@ var_dump($sxe->asXML("$uri.out%00foo")); --EXPECTF-- Warning: simplexml_load_file(): URI must not contain percent-encoded NUL bytes in %s on line %d -Warning: simplexml_load_file(): I/O warning : failed to load external entity "%s/bug79971_1.xml%%r00%rfoo" in %s on line %d +Warning: simplexml_load_file(): I/O warning : failed to load %s bool(false) Warning: SimpleXMLElement::asXML(): URI must not contain percent-encoded NUL bytes in %s on line %d diff --git a/ext/simplexml/tests/gh14638.phpt b/ext/simplexml/tests/gh14638.phpt new file mode 100644 index 0000000000000..abb4e1ac1407c --- /dev/null +++ b/ext/simplexml/tests/gh14638.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-14638: null pointer dereference on object cast __toString after failed XML parsing +--EXTENSIONS-- +simplexml +--CREDITS-- +YuanchengJiang +--FILE-- + + +'; +$root = simplexml_load_string($xml); +try { + $root->__construct("malformed"); +} catch (Exception $e) { + // Intentionally empty +} +echo $root; +?> +--EXPECTF-- +Warning: SimpleXMLElement::__construct(): Entity: line 1: parser error : Start tag expected, '<' not found in %s on line %d + +Warning: SimpleXMLElement::__construct(): malformed in %s on line %d + +Warning: SimpleXMLElement::__construct(): ^ in %s on line %d diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index b8f582871a086..a5f4caa7c5af8 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -3381,7 +3381,6 @@ xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns) } else { smart_str prefix = {0}; int num = ++SOAP_GLOBAL(cur_uniq_ns); - xmlChar *enc_ns; while (1) { smart_str_appendl(&prefix, "ns", 2); @@ -3395,9 +3394,15 @@ xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns) num = ++SOAP_GLOBAL(cur_uniq_ns); } - enc_ns = xmlEncodeSpecialChars(node->doc, BAD_CAST(ns)); + /* Starting with libxml 2.13, we don't have to do this workaround anymore, otherwise we get double-encoded + * entities. See libxml2 commit f506ec66547ef9bac97a2bf306d368ecea8c0c9e. */ +#if LIBXML_VERSION < 21300 + xmlChar *enc_ns = xmlEncodeSpecialChars(node->doc, BAD_CAST(ns)); xmlns = xmlNewNs(node->doc->children, enc_ns, BAD_CAST(prefix.s ? ZSTR_VAL(prefix.s) : "")); xmlFree(enc_ns); +#else + xmlns = xmlNewNs(node->doc->children, BAD_CAST(ns), BAD_CAST(prefix.s ? ZSTR_VAL(prefix.s) : "")); +#endif smart_str_free(&prefix); } } diff --git a/ext/soap/php_xml.c b/ext/soap/php_xml.c index 3ff7aa055fd33..20fd91ac4b49e 100644 --- a/ext/soap/php_xml.c +++ b/ext/soap/php_xml.c @@ -92,13 +92,16 @@ xmlDocPtr soap_xmlParseFile(const char *filename) bool old; php_libxml_sanitize_parse_ctxt_options(ctxt); + /* TODO: In libxml2 2.14.0 change this to the new options API so we don't rely on deprecated APIs. */ + PHP_LIBXML_IGNORE_DEPRECATIONS_START ctxt->keepBlanks = 0; + ctxt->options |= XML_PARSE_HUGE; + PHP_LIBXML_IGNORE_DEPRECATIONS_END ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace; ctxt->sax->comment = soap_Comment; ctxt->sax->warning = NULL; ctxt->sax->error = NULL; /*ctxt->sax->fatalError = NULL;*/ - ctxt->options |= XML_PARSE_HUGE; old = php_libxml_disable_entity_loader(1); xmlParseDocument(ctxt); php_libxml_disable_entity_loader(old); @@ -146,7 +149,10 @@ xmlDocPtr soap_xmlParseMemory(const void *buf, size_t buf_size) ctxt->sax->warning = NULL; ctxt->sax->error = NULL; /*ctxt->sax->fatalError = NULL;*/ + /* TODO: In libxml2 2.14.0 change this to the new options API so we don't rely on deprecated APIs. */ + PHP_LIBXML_IGNORE_DEPRECATIONS_START ctxt->options |= XML_PARSE_HUGE; + PHP_LIBXML_IGNORE_DEPRECATIONS_END old = php_libxml_disable_entity_loader(1); xmlParseDocument(ctxt); php_libxml_disable_entity_loader(old); diff --git a/ext/soap/tests/bugs/bug42151.phpt b/ext/soap/tests/bugs/bug42151.phpt index 6f5c0c4207766..2f9c1830ad39c 100644 --- a/ext/soap/tests/bugs/bug42151.phpt +++ b/ext/soap/tests/bugs/bug42151.phpt @@ -25,8 +25,8 @@ try { } echo "ok\n"; ?> ---EXPECT-- -SOAP-ERROR: Parsing WSDL: Couldn't load from 'httpx://' : failed to load external entity "httpx://" +--EXPECTF-- +SOAP-ERROR: Parsing WSDL: Couldn't load from 'httpx://' : failed to load %s ok I don't get executed either. diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index b996764c1aca1..00f25ecbbc4b3 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -118,9 +118,11 @@ static void spl_object_storage_free_hash(spl_SplObjectStorage *intern, zend_hash static void spl_object_storage_dtor(zval *element) /* {{{ */ { spl_SplObjectStorageElement *el = Z_PTR_P(element); - zend_object_release(el->obj); - zval_ptr_dtor(&el->inf); - efree(el); + if (el) { + zend_object_release(el->obj); + zval_ptr_dtor(&el->inf); + efree(el); + } } /* }}} */ static spl_SplObjectStorageElement* spl_object_storage_get(spl_SplObjectStorage *intern, zend_hash_key *key) /* {{{ */ @@ -168,8 +170,10 @@ static spl_SplObjectStorageElement *spl_object_storage_attach_handle(spl_SplObje return pelement; } + /* NULL initialization necessary because `spl_object_storage_create_element` could bail out due to OOM. */ + ZVAL_PTR(entry_zv, NULL); pelement = spl_object_storage_create_element(obj, inf); - ZVAL_PTR(entry_zv, pelement); + Z_PTR_P(entry_zv) = pelement; return pelement; } /* }}} */ diff --git a/ext/spl/tests/gh14639.phpt b/ext/spl/tests/gh14639.phpt new file mode 100644 index 0000000000000..1b6f621d27bd3 --- /dev/null +++ b/ext/spl/tests/gh14639.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-14639 (Member access within null pointer in ext/spl/spl_observer.c) +--INI-- +memory_limit=2M +--SKIPIF-- + +--FILE-- + 0; $i--) { + $object = new StdClass(); + $object->a = str_repeat("a", 2); + $b->attach($object); +} +?> +--EXPECTF-- +Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/ext/standard/array.c b/ext/standard/array.c index 30868a47b5932..b6f78fad28611 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2887,6 +2887,10 @@ PHP_FUNCTION(range) step = Z_LVAL_P(user_step); /* We only want positive step values. */ if (step < 0) { + if (UNEXPECTED(step == ZEND_LONG_MIN)) { + zend_argument_value_error(3, "must be greater than " ZEND_LONG_FMT, step); + RETURN_THROWS(); + } is_step_negative = true; step *= -1; } diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 746465d9f27a7..97001bcacbf7d 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -1220,6 +1220,7 @@ PHP_FUNCTION(time_sleep_until) struct timespec php_req, php_rem; uint64_t current_ns, target_ns, diff_ns; const uint64_t ns_per_sec = 1000000000; + const double top_target_sec = (double)(UINT64_MAX / ns_per_sec); ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_DOUBLE(target_secs) @@ -1229,6 +1230,11 @@ PHP_FUNCTION(time_sleep_until) RETURN_FALSE; } + if (UNEXPECTED(!(target_secs >= 0 && target_secs <= top_target_sec))) { + zend_argument_value_error(1, "must be between 0 and %" PRIu64, (uint64_t)top_target_sec); + RETURN_THROWS(); + } + target_ns = (uint64_t) (target_secs * ns_per_sec); current_ns = ((uint64_t) tm.tv_sec) * ns_per_sec + ((uint64_t) tm.tv_usec) * 1000; if (target_ns < current_ns) { diff --git a/ext/standard/filestat.c b/ext/standard/filestat.c index 62be6f01c887f..1d83dcfe940df 100644 --- a/ext/standard/filestat.c +++ b/ext/standard/filestat.c @@ -279,13 +279,25 @@ PHPAPI zend_result php_get_gid_by_name(const char *name, gid_t *gid) struct group *retgrptr; long grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX); char *grbuf; + int err; if (grbuflen < 1) { - return FAILURE; + grbuflen = 1024; } - +# if ZEND_DEBUG + /* Test retry logic */ + grbuflen = 1; +# endif grbuf = emalloc(grbuflen); - if (getgrnam_r(name, &gr, grbuf, grbuflen, &retgrptr) != 0 || retgrptr == NULL) { + +try_again: + err = getgrnam_r(name, &gr, grbuf, grbuflen, &retgrptr); + if (err != 0 || retgrptr == NULL) { + if (err == ERANGE) { + grbuflen *= 2; + grbuf = erealloc(grbuf, grbuflen); + goto try_again; + } efree(grbuf); return FAILURE; } @@ -405,13 +417,25 @@ PHPAPI zend_result php_get_uid_by_name(const char *name, uid_t *uid) struct passwd *retpwptr = NULL; long pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); char *pwbuf; + int err; if (pwbuflen < 1) { - return FAILURE; + pwbuflen = 1024; } - +# if ZEND_DEBUG + /* Test retry logic */ + pwbuflen = 1; +# endif pwbuf = emalloc(pwbuflen); - if (getpwnam_r(name, &pw, pwbuf, pwbuflen, &retpwptr) != 0 || retpwptr == NULL) { + +try_again: + err = getpwnam_r(name, &pw, pwbuf, pwbuflen, &retpwptr); + if (err != 0 || retpwptr == NULL) { + if (err == EAGAIN) { + pwbuflen *= 2; + pwbuf = erealloc(pwbuf, pwbuflen); + goto try_again; + } efree(pwbuf); return FAILURE; } diff --git a/ext/standard/string.c b/ext/standard/string.c index 266f8c93c15dd..577efbedf5f1a 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -3224,7 +3224,7 @@ PHP_FUNCTION(strtr) /* case_sensitive */ true, NULL)); } else { - zend_long dummy; + zend_long dummy = 0; RETVAL_STR(php_str_to_str_ex(str, ZSTR_VAL(str_key), ZSTR_LEN(str_key), ZSTR_VAL(replace), ZSTR_LEN(replace), &dummy)); diff --git a/ext/standard/tests/array/gh14775.phpt b/ext/standard/tests/array/gh14775.phpt new file mode 100644 index 0000000000000..df4db76031ecb --- /dev/null +++ b/ext/standard/tests/array/gh14775.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-14775: Range negative step overflow +--FILE-- +getMessage() . PHP_EOL; +} +--EXPECTF-- +range(): Argument #3 ($step) must be greater than %s diff --git a/ext/standard/tests/misc/gh14774.phpt b/ext/standard/tests/misc/gh14774.phpt new file mode 100644 index 0000000000000..1f9cd921e03a6 --- /dev/null +++ b/ext/standard/tests/misc/gh14774.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-14774 time_sleep_until overflow +--SKIPIF-- + +--FILE-- +getMessage() . PHP_EOL; + } +} +?> +--EXPECTF-- +time_sleep_until(): Argument #1 ($timestamp) must be between 0 and %d +time_sleep_until(): Argument #1 ($timestamp) must be between 0 and %d +time_sleep_until(): Argument #1 ($timestamp) must be between 0 and %d +time_sleep_until(): Argument #1 ($timestamp) must be between 0 and %d +time_sleep_until(): Argument #1 ($timestamp) must be between 0 and %d +time_sleep_until(): Argument #1 ($timestamp) must be between 0 and %d diff --git a/ext/standard/tests/streams/gh14930.phpt b/ext/standard/tests/streams/gh14930.phpt new file mode 100644 index 0000000000000..7e034a81235a7 --- /dev/null +++ b/ext/standard/tests/streams/gh14930.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-14930: Custom stream wrapper dir_readdir output truncated to 255 characters in PHP 8.3 +--FILE-- + +--EXPECT-- +string(288) "very-long-filename-ieNoquiaC6ijeiy9beejaiphoriejo2cheehooGou8uhoh7eh0gefahyuQuohd7eec9auso9eeFah2Maedohsemi1eetoo5fo5biePh5eephai7SiuguipouLeemequ2oope9aigoQu5efak2aLeri9ithaiJ9eew3dianaiHoo1aexaighiitee6geghiequ5nohhiikahwee8ohk2Soip2Aikeithohdeitiedeiku7DiTh2eep3deitiedeiku7DiTh2ee.txt" diff --git a/ext/standard/tests/strings/chunk_split_variation1_32bit.phpt b/ext/standard/tests/strings/chunk_split_variation1_32bit.phpt index b4bef8add4103..03a101eb2e43d 100644 --- a/ext/standard/tests/strings/chunk_split_variation1_32bit.phpt +++ b/ext/standard/tests/strings/chunk_split_variation1_32bit.phpt @@ -17,4 +17,4 @@ var_dump(chunk_split($a,$b,$c)); --EXPECTF-- *** Testing chunk_split() : unexpected large 'end' string argument variation 1 *** -Fatal error: %rAllowed memory size of %d bytes exhausted%s\(tried to allocate %d bytes\)|Possible integer overflow in memory allocation \(4294901777 \+ 2097152\)%r in %s on line %d +Fatal error: %rAllowed memory size of %d bytes exhausted%s\(tried to allocate %d bytes\)|Possible integer overflow in memory allocation \(4294901777 \+ %d\)%r in %s on line %d diff --git a/ext/standard/tests/strings/wordwrap_memory_limit.phpt b/ext/standard/tests/strings/wordwrap_memory_limit.phpt index 21340153faea1..e64aef96c9a14 100644 --- a/ext/standard/tests/strings/wordwrap_memory_limit.phpt +++ b/ext/standard/tests/strings/wordwrap_memory_limit.phpt @@ -2,7 +2,7 @@ No overflow should occur during the memory_limit check for wordwrap() --SKIPIF-- --INI-- diff --git a/ext/standard/tests/strings/wordwrap_memory_limit_win32.phpt b/ext/standard/tests/strings/wordwrap_memory_limit_32bit.phpt similarity index 55% rename from ext/standard/tests/strings/wordwrap_memory_limit_win32.phpt rename to ext/standard/tests/strings/wordwrap_memory_limit_32bit.phpt index e0e76b5800ce2..36d22cc859b5b 100644 --- a/ext/standard/tests/strings/wordwrap_memory_limit_win32.phpt +++ b/ext/standard/tests/strings/wordwrap_memory_limit_32bit.phpt @@ -2,7 +2,7 @@ No overflow should occur during the memory_limit check for wordwrap() --SKIPIF-- --INI-- @@ -16,4 +16,4 @@ wordwrap($str, 1, $str2); ?> --EXPECTF-- -Fatal error: Possible integer overflow in memory allocation (4294901777 + %d) in %s on line %d +Fatal error: %rAllowed memory size of %d bytes exhausted%s\(tried to allocate %d bytes\)|Possible integer overflow in memory allocation \(4294901777 \+ %d\)%r in %s on line %d diff --git a/ext/tidy/tests/parsing_file_too_large.phpt b/ext/tidy/tests/parsing_file_too_large.phpt index 46196c0a5fdce..a0118ba9ebdce 100644 --- a/ext/tidy/tests/parsing_file_too_large.phpt +++ b/ext/tidy/tests/parsing_file_too_large.phpt @@ -47,6 +47,12 @@ try { } catch (\Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; } + +try { + tidy_repair_file($path); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} ?> --CLEAN-- parser->myDoc, name); - if (ret == NULL || (parser->parser->instate != XML_PARSER_ENTITY_VALUE && parser->parser->instate != XML_PARSER_ATTRIBUTE_VALUE)) { + if (ret == NULL || parser->parser->instate == XML_PARSER_CONTENT) { if (ret == NULL || ret->etype == XML_INTERNAL_GENERAL_ENTITY || ret->etype == XML_INTERNAL_PARAMETER_ENTITY || ret->etype == XML_INTERNAL_PREDEFINED_ENTITY) { /* Predefined entities will expand unless no cdata handler is present */ if (parser->h_default && ! (ret && ret->etype == XML_INTERNAL_PREDEFINED_ENTITY && parser->h_cdata)) { @@ -471,13 +471,13 @@ XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *m } php_libxml_sanitize_parse_ctxt_options(parser->parser); - xmlCtxtUseOptions(parser->parser, XML_PARSE_OLDSAX); + xmlCtxtUseOptions(parser->parser, XML_PARSE_OLDSAX | XML_PARSE_NOENT); - parser->parser->replaceEntities = 1; parser->parser->wellFormed = 0; if (sep != NULL) { + /* Note: sax2 flag will be set due to the magic number in `initialized` in php_xml_compat_handlers */ + ZEND_ASSERT(parser->parser->sax->initialized == XML_SAX2_MAGIC); parser->use_namespace = 1; - parser->parser->sax2 = 1; parser->_ns_separator = xmlStrdup(sep); } else { /* Reset flag as XML_SAX2_MAGIC is needed for xmlCreatePushParserCtxt @@ -563,10 +563,14 @@ XML_SetEndNamespaceDeclHandler(XML_Parser parser, XML_EndNamespaceDeclHandler en PHP_XML_API int XML_Parse(XML_Parser parser, const XML_Char *data, int data_len, int is_final) { - int error; + int error = xmlParseChunk(parser->parser, (char *) data, data_len, is_final); - error = xmlParseChunk(parser->parser, (char *) data, data_len, is_final); - return !error && parser->parser->lastError.level <= XML_ERR_WARNING; + if (!error) { + const xmlError *error_data = xmlCtxtGetLastError(parser->parser); + return !error_data || error_data->level <= XML_ERR_WARNING; + } + + return 0; } PHP_XML_API int @@ -705,8 +709,21 @@ XML_GetCurrentColumnNumber(XML_Parser parser) PHP_XML_API int XML_GetCurrentByteIndex(XML_Parser parser) { - return parser->parser->input->consumed + - (parser->parser->input->cur - parser->parser->input->base); + /* We have to temporarily disable the encoder to satisfy the note from the manual: + * "This function returns byte index according to UTF-8 encoded text disregarding if input is in another encoding." + * Although that should probably be corrected at one point? (TODO) */ + xmlCharEncodingHandlerPtr encoder = NULL; + xmlParserInputPtr input = parser->parser->input; + if (input->buf) { + encoder = input->buf->encoder; + input->buf->encoder = NULL; + } + long result = xmlByteConsumed(parser->parser); + if (encoder) { + input->buf->encoder = encoder; + } + /* TODO: at one point this should return long probably to make sure that files greater than 2 GiB are handled correctly. */ + return (int) result; } PHP_XML_API int @@ -714,8 +731,7 @@ XML_GetCurrentByteCount(XML_Parser parser) { /* WARNING: this is identical to ByteIndex; it should probably * be different */ - return parser->parser->input->consumed + - (parser->parser->input->cur - parser->parser->input->base); + return XML_GetCurrentByteIndex(parser); } PHP_XML_API const XML_Char *XML_ExpatVersion(void) diff --git a/ext/xml/tests/gh14834.phpt b/ext/xml/tests/gh14834.phpt new file mode 100644 index 0000000000000..1b7dfd1575722 --- /dev/null +++ b/ext/xml/tests/gh14834.phpt @@ -0,0 +1,34 @@ +--TEST-- +GH-14834 (Error installing PHP when --with-pear is used) +--EXTENSIONS-- +xml +--SKIPIF-- + +--FILE-- + + +]> + + &foo; + +XML; + +$parser = xml_parser_create(); +xml_set_character_data_handler($parser, function($_, $data) { + var_dump($data); +}); +xml_parse($parser, $xml, true); +?> +--EXPECT-- +string(3) " + " +string(3) "ent" +string(7) " & " +string(1) " +" diff --git a/ext/xmlwriter/php_xmlwriter.c b/ext/xmlwriter/php_xmlwriter.c index abb135780887b..aacbfdb644709 100644 --- a/ext/xmlwriter/php_xmlwriter.c +++ b/ext/xmlwriter/php_xmlwriter.c @@ -900,7 +900,8 @@ static void php_xmlwriter_flush(INTERNAL_FUNCTION_PARAMETERS, int force_string) } output_bytes = xmlTextWriterFlush(ptr); if (buffer) { - RETVAL_STRING((char *) buffer->content); + const xmlChar *content = xmlBufferContent(buffer); + RETVAL_STRING((const char *) content); if (empty) { xmlBufferEmpty(buffer); } diff --git a/ext/xsl/tests/skip_upstream_issue113.inc b/ext/xsl/tests/skip_upstream_issue113.inc new file mode 100644 index 0000000000000..a08bc4f037c2f --- /dev/null +++ b/ext/xsl/tests/skip_upstream_issue113.inc @@ -0,0 +1,5 @@ +hasExsltSupport()) die('skip EXSLT support not available'); if (LIBXSLT_VERSION < 10130) die('skip too old libxsl'); +require __DIR__.'/skip_upstream_issue113.inc'; ?> --FILE-- getIterator(); +try { + clone $it; +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Trying to clone an uncloneable object of class InternalIterator +TraversableTest::drop diff --git a/ext/zlib/tests/gzfile_basic2.phpt b/ext/zlib/tests/gzfile_basic2.phpt index f53aec8da0322..2b59656a6f314 100644 --- a/ext/zlib/tests/gzfile_basic2.phpt +++ b/ext/zlib/tests/gzfile_basic2.phpt @@ -9,7 +9,7 @@ hello world is a very common test for all languages EOT; -$dirname = 'gzfile_temp'; +$dirname = 'gzfile_temp2'; $filename = $dirname.'/gzfile_basic2.txt'; mkdir($dirname); $h = fopen($filename, 'w'); diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c index d7644dcd06cd3..62f6b4de40433 100644 --- a/main/fopen_wrappers.c +++ b/main/fopen_wrappers.c @@ -374,26 +374,38 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle) if (s) { /* if there is no path name after the file, do not bother */ char user[32]; /* to try open the directory */ + + length = s - (path_info + 2); + if (length > sizeof(user) - 1) { + length = sizeof(user) - 1; + } + memcpy(user, path_info + 2, length); + user[length] = '\0'; + struct passwd *pw; #if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX) struct passwd pwstruc; long pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); char *pwbuf; + int err; if (pwbuflen < 1) { - return FAILURE; + pwbuflen = 1024; } - +# if ZEND_DEBUG + /* Test retry logic */ + pwbuflen = 1; +# endif pwbuf = emalloc(pwbuflen); -#endif - length = s - (path_info + 2); - if (length > sizeof(user) - 1) { - length = sizeof(user) - 1; - } - memcpy(user, path_info + 2, length); - user[length] = '\0'; -#if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX) - if (getpwnam_r(user, &pwstruc, pwbuf, pwbuflen, &pw)) { + +try_again: + err = getpwnam_r(user, &pwstruc, pwbuf, pwbuflen, &pw); + if (err) { + if (err == ERANGE) { + pwbuflen *= 2; + pwbuf = erealloc(pwbuf, pwbuflen); + goto try_again; + } efree(pwbuf); return FAILURE; } diff --git a/main/main.c b/main/main.c index 3c9c55129e971..eb6f17c1eed92 100644 --- a/main/main.c +++ b/main/main.c @@ -1471,12 +1471,25 @@ PHPAPI char *php_get_current_user(void) struct passwd *retpwptr = NULL; int pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); char *pwbuf; + int err; if (pwbuflen < 1) { - return ""; + pwbuflen = 1024; } +# if ZEND_DEBUG + /* Test retry logic */ + pwbuflen = 1; +# endif pwbuf = emalloc(pwbuflen); - if (getpwuid_r(pstat->st_uid, &_pw, pwbuf, pwbuflen, &retpwptr) != 0) { + +try_again: + err = getpwuid_r(pstat->st_uid, &_pw, pwbuf, pwbuflen, &retpwptr); + if (err != 0) { + if (err == ERANGE) { + pwbuflen *= 2; + pwbuf = erealloc(pwbuf, pwbuflen); + goto try_again; + } efree(pwbuf); return ""; } diff --git a/main/output.c b/main/output.c index 57a61e4b93651..c2cb0ceab0112 100644 --- a/main/output.c +++ b/main/output.c @@ -360,7 +360,11 @@ PHPAPI int php_output_get_level(void) PHPAPI int php_output_get_contents(zval *p) { if (OG(active)) { - ZVAL_STRINGL(p, OG(active)->buffer.data, OG(active)->buffer.used); + if (OG(active)->buffer.used) { + ZVAL_STRINGL(p, OG(active)->buffer.data, OG(active)->buffer.used); + } else { + ZVAL_EMPTY_STRING(p); + } return SUCCESS; } else { ZVAL_NULL(p); diff --git a/main/php_streams.h b/main/php_streams.h index 31b80de986053..33b14ff4eb3df 100644 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -107,11 +107,7 @@ typedef struct _php_stream_statbuf { } php_stream_statbuf; typedef struct _php_stream_dirent { -#ifdef NAME_MAX - char d_name[NAME_MAX + 1]; -#else char d_name[MAXPATHLEN]; -#endif unsigned char d_type; } php_stream_dirent; diff --git a/main/php_version.h b/main/php_version.h index 1ba99e780ae96..a0988355140e4 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 3 -#define PHP_RELEASE_VERSION 9 -#define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.3.9-dev" -#define PHP_VERSION_ID 80309 +#define PHP_RELEASE_VERSION 10 +#define PHP_EXTRA_VERSION "" +#define PHP_VERSION "8.3.10" +#define PHP_VERSION_ID 80310 diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index a69ac171cface..a58385456b04d 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -229,13 +229,13 @@ static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */ if (zend_vm_kind() != ZEND_VM_KIND_HYBRID) { /* phpdbg cannot work JIT-ed code */ - zend_string *key = zend_string_init(ZEND_STRL("opcache.jit"), 1); - zend_string *value = zend_string_init(ZEND_STRL("off"), 1); + zend_string *key = zend_string_init(ZEND_STRL("opcache.jit"), false); + zend_string *value = zend_string_init(ZEND_STRL("off"), false); - zend_alter_ini_entry(key, value, ZEND_INI_SYSTEM, ZEND_INI_STAGE_STARTUP); + zend_alter_ini_entry_ex(key, value, ZEND_INI_SYSTEM, ZEND_INI_STAGE_STARTUP, false); - zend_string_release(key); - zend_string_release(value); + zend_string_release_ex(key, false); + zend_string_release_ex(value, false); } return SUCCESS; @@ -845,7 +845,7 @@ static void php_sapi_phpdbg_register_vars(zval *track_vars_array) /* {{{ */ static inline size_t php_sapi_phpdbg_ub_write(const char *message, size_t length) /* {{{ */ { - return phpdbg_script(P_STDOUT, "%.*s", (int) length, message); + return phpdbg_process_print(PHPDBG_G(io)[PHPDBG_STDOUT].fd, P_STDOUT, message, (int) length); } /* }}} */ /* beginning of struct, see main/streams/plain_wrapper.c line 111 */ diff --git a/sapi/phpdbg/phpdbg_out.c b/sapi/phpdbg/phpdbg_out.c index af2f3b98d2bad..63b61fb8eab04 100644 --- a/sapi/phpdbg/phpdbg_out.c +++ b/sapi/phpdbg/phpdbg_out.c @@ -40,7 +40,7 @@ PHPDBG_API int _phpdbg_asprintf(char **buf, const char *format, ...) { return ret; } -static int phpdbg_process_print(int fd, int type, const char *msg, int msglen) { +int phpdbg_process_print(int fd, int type, const char *msg, int msglen) { char *msgout = NULL; int msgoutlen = FAILURE; diff --git a/sapi/phpdbg/phpdbg_out.h b/sapi/phpdbg/phpdbg_out.h index 828e147a1b7e9..1a54bb7ec284a 100644 --- a/sapi/phpdbg/phpdbg_out.h +++ b/sapi/phpdbg/phpdbg_out.h @@ -59,6 +59,8 @@ PHPDBG_API void phpdbg_free_err_buf(void); PHPDBG_API void phpdbg_activate_err_buf(bool active); PHPDBG_API int phpdbg_output_err_buf(const char *strfmt, ...); +int phpdbg_process_print(int fd, int type, const char *msg, int msglen); + /* {{{ For separation */ #define SEPARATE "------------------------------------------------" /* }}} */ diff --git a/sapi/phpdbg/tests/gh10715.phpt b/sapi/phpdbg/tests/gh10715.phpt index 13edd9afdd8f0..63d98cae10736 100644 Binary files a/sapi/phpdbg/tests/gh10715.phpt and b/sapi/phpdbg/tests/gh10715.phpt differ diff --git a/sapi/phpdbg/tests/gh14553.phpt b/sapi/phpdbg/tests/gh14553.phpt new file mode 100644 index 0000000000000..bcf61c0a9fb4d --- /dev/null +++ b/sapi/phpdbg/tests/gh14553.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-14553 (Bug in phpdbg8.3 (also 8.1 and 8.2) echo output - trimmed at NULL byte (?)) +--PHPDBG-- +r +q +--FILE-- + +--EXPECTF-- +[Successful compilation of %s] +prompt> hello%0world +[Script ended normally] +prompt> diff --git a/tests/output/gh14808.phpt b/tests/output/gh14808.phpt new file mode 100644 index 0000000000000..32addcbc76370 --- /dev/null +++ b/tests/output/gh14808.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-14808 (Unexpected null pointer in Zend/zend_string.h with empty output buffer) +--EXTENSIONS-- +iconv +--FILE-- + +--EXPECTF-- +Warning: Undefined variable $args in %s on line %d +NULL +string(0) ""