diff --git a/.github/actions/test-linux/action.yml b/.github/actions/test-linux/action.yml index f6d726a2f71dd..a56ed2823d7ac 100644 --- a/.github/actions/test-linux/action.yml +++ b/.github/actions/test-linux/action.yml @@ -9,6 +9,9 @@ inputs: jitType: default: 'disable' required: false + idleCpu: + default: 'false' + required: false runs: using: composite steps: @@ -36,7 +39,7 @@ runs: sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \ -d opcache.jit=${{ inputs.jitType }} \ -d opcache.jit_buffer_size=16M \ - -j$(/usr/bin/nproc) \ + ${{ inputs.idleCpu == 'true' && '-j$(($(/usr/bin/nproc) - 1))' || '-j$(/usr/bin/nproc)' }} \ -g FAIL,BORK,LEAK,XLEAK \ --no-progress \ --offline \ diff --git a/.github/actions/test-macos/action.yml b/.github/actions/test-macos/action.yml index 63bccece39ed0..0090f6a1cb337 100644 --- a/.github/actions/test-macos/action.yml +++ b/.github/actions/test-macos/action.yml @@ -21,7 +21,7 @@ runs: sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \ -d opcache.jit=${{ inputs.jitType }} \ -d opcache.jit_buffer_size=16M \ - -j$(sysctl -n hw.ncpu) \ + -j$(($(sysctl -n hw.ncpu) - 1)) \ -g FAIL,BORK,LEAK,XLEAK \ --no-progress \ --offline \ diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index dae430f225bae..a8fdd0a867bec 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -82,6 +82,7 @@ jobs: testArtifacts: ${{ matrix.branch.name }}_${{ matrix.name }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }} runTestsParameters: >- ${{ matrix.run_tests_parameters }} + idleCpu: ${{ matrix.asan && 'true' || 'false' }} - name: Test Tracing JIT uses: ./.github/actions/test-linux with: diff --git a/.travis.yml b/.travis.yml index 6c51e13a0fab5..9f764251afffc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -85,7 +85,7 @@ before_script: # Run PHPs run-tests.php script: - - travis_wait 60 ./travis/test.sh -d opcache.jit_buffer_size=16M -d opcache.jit=tracing + - ./travis/test.sh -d opcache.jit_buffer_size=16M -d opcache.jit=tracing - sapi/cli/php -d extension_dir=`pwd`/modules -r 'dl("zend_test");' after_success: diff --git a/NEWS b/NEWS index aec27dd8614fe..7c7bdaf0d6933 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,95 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.2.13 +21 Dec 2023, PHP 8.2.14 + +- Core: + . Fixed oss-fuzz #54325 (Use-after-free of name in var-var with malicious + error handler). (ilutov) + . Fixed oss-fuzz #64209 (In-place modification of filename in + php_message_handler_for_zend). (ilutov) + . Fixed bug GH-12758 / GH-12768 (Invalid opline in OOM handlers within + ZEND_FUNC_GET_ARGS and ZEND_BIND_STATIC). (Florian Engelhardt) + . Fix various missing NULL checks. (nielsdos, dstogov) + . Fixed bug GH-12835 (Leak of call->extra_named_params on internal __call). + (ilutov) + +- Date: + . Fixed improbably integer overflow while parsing really large (or small) + Unix timestamps. (Derick) + +- DOM: + . Fixed bug GH-12616 (DOM: Removing XMLNS namespace node results in invalid + default: prefix). (nielsdos) + +- FPM: + . Fixed bug GH-12705 (Segmentation fault in fpm_status_export_to_zval). + (Patrick Prasse) + +- FTP: + . Fixed bug GH-9348 (FTP & SSL session reuse). (nielsdos) + +- Intl: + . Fixed bug GH-12635 (Test bug69398.phpt fails with ICU 74.1). (nielsdos) + +- LibXML: + . Fixed bug GH-12702 (libxml2 2.12.0 issue building from src). (nono303) + . Fixed test failures for libxml2 2.12.0. (nielsdos) + +- MySQLnd: + . Avoid using uninitialised struct. (mikhainin) + . Fixed bug GH-12791 (Possible dereference of NULL in MySQLnd debug code). + (nielsdos) + +- Opcache: + . Fixed JIT bug (Function JIT emits "Uninitialized string offset" warning + at the same time as invalid offset Error). (Girgias) + . Fixed JIT bug (JIT emits "Attempt to assign property of non-object" + warning at the same time as Error is being thrown). (Girgias) + +- OpenSSL: + . Fixed bug #50713 (openssl_pkcs7_verify() may ignore untrusted CAs). + (Jakub Zelenka) + +- PCRE: + . Fixed bug GH-12628 (The gh11374 test fails on Alpinelinux). (nielsdos) + +- PDO PGSQL: + . Fixed the default value of $fetchMode in PDO::pgsqlGetNotify() (kocsismate) + +- PGSQL: + . Fixed bug GH-12763 wrong argument type for pg_untrace. (degtyarov) + +- PHPDBG: + . Fixed bug GH-12675 (MEMORY_LEAK in phpdbg_prompt.c). (nielsdos) + +- SOAP: + . Fixed bug GH-12838 ([SOAP] Temporary WSDL cache files not being deleted). + (nielsdos) + +- SPL: + . Fixed bug GH-12721 (SplFileInfo::getFilename() segfault in combination + with GlobIterator and no directory separator). (nielsdos) + +- SQLite3: + . Fixed bug GH-12633 (sqlite3_defensive.phpt fails with sqlite 3.44.0). + (SakiTakamachi) + +- Standard: + . Fix memory leak in syslog device handling. (danog) + . Fixed bug GH-12621 (browscap segmentation fault when configured in the + vhost). (nielsdos) + . Fixed bug GH-12655 (proc_open() does not take into account references + in the descriptor array). (nielsdos) + +- Streams: + . Fixed bug #79945 (Stream wrappers in imagecreatefrompng causes segfault). + (Jakub Zelenka) + +- Zip: + . Fixed bug GH-12661 (Inconsistency in ZipArchive::addGlob remove_path Option + Behavior). (Remi) + +23 Nov 2023, PHP 8.2.13 - Core: . Fixed double-free of non-interned enum case name. (ilutov) diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 10f8d950ee094..3aefdf53df072 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -235,7 +235,7 @@ static const func_info_t func_infos[] = { F1("mb_convert_variables", MAY_BE_STRING|MAY_BE_FALSE), F1("mb_encode_numericentity", MAY_BE_STRING), F1("mb_decode_numericentity", MAY_BE_STRING), - F1("mb_get_info", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_STRING|MAY_BE_LONG|MAY_BE_FALSE), + F1("mb_get_info", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_STRING|MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_NULL), #if defined(HAVE_MBREGEX) F1("mb_regex_encoding", MAY_BE_STRING|MAY_BE_BOOL), #endif diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index 794f630ac920c..16edb2cc82e46 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -2674,6 +2674,9 @@ static zend_always_inline zend_result _zend_update_type_info( } } if (opline->extended_value == IS_ARRAY) { + if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL)) { + tmp |= MAY_BE_ARRAY_EMPTY; + } if (t1 & MAY_BE_ARRAY) { tmp |= t1 & (MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF); } @@ -3387,6 +3390,9 @@ static zend_always_inline zend_result _zend_update_type_info( arr_type = RES_USE_INFO(); } tmp = MAY_BE_RC1|MAY_BE_ARRAY|arr_type; + if (opline->opcode == ZEND_INIT_ARRAY && opline->op1_type == IS_UNUSED) { + tmp |= MAY_BE_ARRAY_EMPTY; + } if (opline->op1_type != IS_UNUSED && (opline->op2_type == IS_UNUSED || (t2 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE|MAY_BE_STRING)))) { @@ -3667,7 +3673,8 @@ static zend_always_inline zend_result _zend_update_type_info( tmp &= ~MAY_BE_ARRAY_EMPTY; } } - if (((tmp & MAY_BE_ARRAY) && (tmp & MAY_BE_ARRAY_KEY_ANY)) + if (!(tmp & MAY_BE_ARRAY) + || (tmp & MAY_BE_ARRAY_KEY_ANY) || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG || opline->opcode == ZEND_FETCH_DIM_R || opline->opcode == ZEND_FETCH_DIM_IS @@ -3676,9 +3683,7 @@ static zend_always_inline zend_result _zend_update_type_info( UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } else { /* invalid key type */ - tmp = (tmp & (MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ARRAY)) | - (t1 & ~(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)); - UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + return SUCCESS; } COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } diff --git a/Zend/tests/oss_fuzz_54325.phpt b/Zend/tests/oss_fuzz_54325.phpt new file mode 100644 index 0000000000000..d998acf1ffedb --- /dev/null +++ b/Zend/tests/oss_fuzz_54325.phpt @@ -0,0 +1,19 @@ +--TEST-- +oss-fuzz #54325: Fix use-after-free of name in var-var with malicious error handler +--FILE-- + +--EXPECT-- +string(23) "Undefined variable $oof" +object(stdClass)#2 (0) { +} diff --git a/Zend/tests/oss_fuzz_64209.phpt b/Zend/tests/oss_fuzz_64209.phpt new file mode 100644 index 0000000000000..599ae258e5b2c --- /dev/null +++ b/Zend/tests/oss_fuzz_64209.phpt @@ -0,0 +1,13 @@ +--TEST-- +oss-fuzz #64209: Fix in-place modification of filename in php_message_handler_for_zend +--FILE-- + +--EXPECTF-- +Warning: require(://@): Failed to open stream: No such file or directory in %s on line %d + +Fatal error: Uncaught Error: Failed opening required '://@' (include_path='%s') in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/zend.h b/Zend/zend.h index 4ae4b2d8f0670..526bbf078fa7b 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.2.13-dev" +#define ZEND_VERSION "4.2.14" #define ZEND_ENGINE_3 diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 5cebbbc560894..9c4b836caface 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -154,7 +154,7 @@ ZEND_FUNCTION(func_num_args) ZEND_PARSE_PARAMETERS_NONE(); - if (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE) { + if (ex && (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE)) { zend_throw_error(NULL, "func_num_args() must be called from a function context"); RETURN_THROWS(); } @@ -185,7 +185,7 @@ ZEND_FUNCTION(func_get_arg) } ex = EX(prev_execute_data); - if (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE) { + if (ex && (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE)) { zend_throw_error(NULL, "func_get_arg() cannot be called from the global scope"); RETURN_THROWS(); } @@ -223,7 +223,7 @@ ZEND_FUNCTION(func_get_args) ZEND_PARSE_PARAMETERS_NONE(); - if (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE) { + if (ex && (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE)) { zend_throw_error(NULL, "func_get_args() cannot be called from the global scope"); RETURN_THROWS(); } diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 89610f84b5efc..0df529203c1b9 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1417,9 +1417,9 @@ static ZEND_COLD void zend_verify_missing_return_type(const zend_function *zf) zend_verify_return_error(zf, NULL); } -static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_object_as_array(void) +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_object_as_array(const zend_object *object) { - zend_throw_error(NULL, "Cannot use object as array"); + zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(object->ce->name)); } static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_offset(void) @@ -1487,7 +1487,7 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zv } zval_ptr_dtor(&res); } else { - zend_use_object_as_array(); + zend_use_object_as_array(obj); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8ad2c6116d898..2a48b9c3713bb 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1748,6 +1748,10 @@ ZEND_VM_C_LABEL(fetch_this): } else if (type == BP_VAR_IS || type == BP_VAR_UNSET) { retval = &EG(uninitialized_zval); } else { + if (OP1_TYPE == IS_CV) { + /* Keep name alive in case an error handler tries to free it. */ + zend_string_addref(name); + } zend_error(E_WARNING, "Undefined %svariable $%s", (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); if (type == BP_VAR_RW && !EG(exception)) { @@ -1755,6 +1759,9 @@ ZEND_VM_C_LABEL(fetch_this): } else { retval = &EG(uninitialized_zval); } + if (OP1_TYPE == IS_CV) { + zend_string_release(name); + } } /* GLOBAL or $$name variable may be an INDIRECT pointer to CV */ } else if (Z_TYPE_P(retval) == IS_INDIRECT) { @@ -8776,6 +8783,9 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER)) EG(current_execute_data) = call->prev_execute_data; zend_vm_stack_free_args(call); + if (UNEXPECTED(call_info & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) { + zend_free_extra_named_params(call->extra_named_params); + } if (ret == &retval) { zval_ptr_dtor(ret); } @@ -8844,6 +8854,8 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF) variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); + SAVE_OPLINE(); + ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr); if (!ht) { ht = zend_array_dup(EX(func)->op_array.static_variables); @@ -8853,7 +8865,6 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF) value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))); - SAVE_OPLINE(); if (opline->extended_value & ZEND_BIND_REF) { if (Z_TYPE_P(value) == IS_CONSTANT_AST) { if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) { @@ -9307,6 +9318,7 @@ ZEND_VM_HANDLER(172, ZEND_FUNC_GET_ARGS, UNUSED|CONST, UNUSED) } if (result_size) { + SAVE_OPLINE(); uint32_t first_extra_arg = EX(func)->op_array.num_args; ht = zend_new_array(result_size); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 22e9f5b62a8ae..3bc01a597fa6c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3457,6 +3457,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z EG(current_execute_data) = call->prev_execute_data; zend_vm_stack_free_args(call); + if (UNEXPECTED(call_info & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) { + zend_free_extra_named_params(call->extra_named_params); + } if (ret == &retval) { zval_ptr_dtor(ret); } @@ -3598,6 +3601,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_ EG(current_execute_data) = call->prev_execute_data; zend_vm_stack_free_args(call); + if (UNEXPECTED(call_info & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) { + zend_free_extra_named_params(call->extra_named_params); + } if (ret == &retval) { zval_ptr_dtor(ret); } @@ -9859,6 +9865,10 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad } else if (type == BP_VAR_IS || type == BP_VAR_UNSET) { retval = &EG(uninitialized_zval); } else { + if (IS_CONST == IS_CV) { + /* Keep name alive in case an error handler tries to free it. */ + zend_string_addref(name); + } zend_error(E_WARNING, "Undefined %svariable $%s", (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); if (type == BP_VAR_RW && !EG(exception)) { @@ -9866,6 +9876,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad } else { retval = &EG(uninitialized_zval); } + if (IS_CONST == IS_CV) { + zend_string_release(name); + } } /* GLOBAL or $$name variable may be an INDIRECT pointer to CV */ } else if (Z_TYPE_P(retval) == IS_INDIRECT) { @@ -10798,6 +10811,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FUNC_GET_ARGS_SPEC_CONST_UNUSE } if (result_size) { + SAVE_OPLINE(); uint32_t first_extra_arg = EX(func)->op_array.num_args; ht = zend_new_array(result_size); @@ -17667,6 +17681,10 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad } else if (type == BP_VAR_IS || type == BP_VAR_UNSET) { retval = &EG(uninitialized_zval); } else { + if ((IS_TMP_VAR|IS_VAR) == IS_CV) { + /* Keep name alive in case an error handler tries to free it. */ + zend_string_addref(name); + } zend_error(E_WARNING, "Undefined %svariable $%s", (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); if (type == BP_VAR_RW && !EG(exception)) { @@ -17674,6 +17692,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad } else { retval = &EG(uninitialized_zval); } + if ((IS_TMP_VAR|IS_VAR) == IS_CV) { + zend_string_release(name); + } } /* GLOBAL or $$name variable may be an INDIRECT pointer to CV */ } else if (Z_TYPE_P(retval) == IS_INDIRECT) { @@ -36289,6 +36310,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FUNC_GET_ARGS_SPEC_UNUSED_UNUS } if (result_size) { + SAVE_OPLINE(); uint32_t first_extra_arg = EX(func)->op_array.num_args; ht = zend_new_array(result_size); @@ -47240,6 +47262,10 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad } else if (type == BP_VAR_IS || type == BP_VAR_UNSET) { retval = &EG(uninitialized_zval); } else { + if (IS_CV == IS_CV) { + /* Keep name alive in case an error handler tries to free it. */ + zend_string_addref(name); + } zend_error(E_WARNING, "Undefined %svariable $%s", (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); if (type == BP_VAR_RW && !EG(exception)) { @@ -47247,6 +47273,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad } else { retval = &EG(uninitialized_zval); } + if (IS_CV == IS_CV) { + zend_string_release(name); + } } /* GLOBAL or $$name variable may be an INDIRECT pointer to CV */ } else if (Z_TYPE_P(retval) == IS_INDIRECT) { @@ -48682,6 +48711,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_UNUSED_HAN variable_ptr = EX_VAR(opline->op1.var); + SAVE_OPLINE(); + ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr); if (!ht) { ht = zend_array_dup(EX(func)->op_array.static_variables); @@ -48691,7 +48722,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_UNUSED_HAN value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))); - SAVE_OPLINE(); if (opline->extended_value & ZEND_BIND_REF) { if (Z_TYPE_P(value) == IS_CONSTANT_AST) { if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) { diff --git a/configure.ac b/configure.ac index c8521f8f04133..d11f13f854096 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.2.13-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.2.14],[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 @@ -1581,6 +1581,23 @@ if test "$PHP_UNDEFINED_SANITIZER" = "yes"; then CFLAGS="$CFLAGS -fno-sanitize=object-size" CXXFLAGS="$CFLAGS -fno-sanitize=object-size" ]) + + dnl Clang 17 adds stricter function pointer compatibility checks where pointer args cannot be + dnl cast to void*. In that case, set -fno-sanitize=function. + OLD_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-sanitize-recover=undefined" + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +void foo(char *string) {} +int main(void) { + void (*f)(void *) = (void (*)(void *))foo; + f("foo"); +} + ]])],,[ubsan_needs_no_function=yes],) + CFLAGS="$OLD_CFLAGS" + if test "$ubsan_needs_no_function" = yes; then + CFLAGS="$CFLAGS -fno-sanitize=function" + CXXFLAGS="$CFLAGS -fno-sanitize=function" + fi ], [AC_MSG_ERROR([UndefinedBehaviorSanitizer is not available])]) fi diff --git a/ext/date/lib/parse_date.c b/ext/date/lib/parse_date.c index 0b19c4fa4e993..a53fdc215472c 100644 --- a/ext/date/lib/parse_date.c +++ b/ext/date/lib/parse_date.c @@ -1,4 +1,4 @@ -/* Generated by re2c 1.0.3 on Thu Aug 3 09:42:12 2023 */ +/* Generated by re2c 1.0.3 on Thu Nov 23 16:02:28 2023 */ #line 1 "ext/date/lib/parse_date.re" /* * The MIT License (MIT) @@ -713,6 +713,17 @@ static const timelib_relunit* timelib_lookup_relunit(const char **ptr) return value; } +static void add_with_overflow(Scanner *s, timelib_sll *e, timelib_sll amount, int multiplier) +{ +#if defined(__has_builtin) && __has_builtin(__builtin_saddll_overflow) + if (__builtin_saddll_overflow(*e, amount * multiplier, e)) { + add_error(s, TIMELIB_ERR_NUMBER_OUT_OF_RANGE, "Number out of range"); + } +#else + *e += (amount * multiplier); +#endif +} + /** * The time_part parameter is a flag. It can be TIMELIB_TIME_PART_KEEP in case * the time portion should not be reset to midnight, or @@ -728,13 +739,13 @@ static void timelib_set_relative(const char **ptr, timelib_sll amount, int behav } switch (relunit->unit) { - case TIMELIB_MICROSEC: s->time->relative.us += amount * relunit->multiplier; break; - case TIMELIB_SECOND: s->time->relative.s += amount * relunit->multiplier; break; - case TIMELIB_MINUTE: s->time->relative.i += amount * relunit->multiplier; break; - case TIMELIB_HOUR: s->time->relative.h += amount * relunit->multiplier; break; - case TIMELIB_DAY: s->time->relative.d += amount * relunit->multiplier; break; - case TIMELIB_MONTH: s->time->relative.m += amount * relunit->multiplier; break; - case TIMELIB_YEAR: s->time->relative.y += amount * relunit->multiplier; break; + case TIMELIB_MICROSEC: add_with_overflow(s, &s->time->relative.us, amount, relunit->multiplier); break; + case TIMELIB_SECOND: add_with_overflow(s, &s->time->relative.s, amount, relunit->multiplier); break; + case TIMELIB_MINUTE: add_with_overflow(s, &s->time->relative.i, amount, relunit->multiplier); break; + case TIMELIB_HOUR: add_with_overflow(s, &s->time->relative.h, amount, relunit->multiplier); break; + case TIMELIB_DAY: add_with_overflow(s, &s->time->relative.d, amount, relunit->multiplier); break; + case TIMELIB_MONTH: add_with_overflow(s, &s->time->relative.m, amount, relunit->multiplier); break; + case TIMELIB_YEAR: add_with_overflow(s, &s->time->relative.y, amount, relunit->multiplier); break; case TIMELIB_WEEKDAY: TIMELIB_HAVE_WEEKDAY_RELATIVE(); @@ -1003,11 +1014,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) std: s->tok = cursor; s->len = 0; -#line 1136 "ext/date/lib/parse_date.re" +#line 1147 "ext/date/lib/parse_date.re" -#line 1011 "" +#line 1022 "" { YYCTYPE yych; unsigned int yyaccept = 0; @@ -1188,23 +1199,23 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(2, *YYCURSOR); ++YYCURSOR; YYDEBUG(3, *YYCURSOR); -#line 1969 "ext/date/lib/parse_date.re" +#line 1980 "ext/date/lib/parse_date.re" { s->pos = cursor; s->line++; goto std; } -#line 1197 "" +#line 1208 "" yy4: YYDEBUG(4, *YYCURSOR); ++YYCURSOR; yy5: YYDEBUG(5, *YYCURSOR); -#line 1975 "ext/date/lib/parse_date.re" +#line 1986 "ext/date/lib/parse_date.re" { add_error(s, TIMELIB_ERR_UNEXPECTED_CHARACTER, "Unexpected character"); goto std; } -#line 1208 "" +#line 1219 "" yy6: YYDEBUG(6, *YYCURSOR); yyaccept = 0; @@ -1219,11 +1230,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy58; yy8: YYDEBUG(8, *YYCURSOR); -#line 1964 "ext/date/lib/parse_date.re" +#line 1975 "ext/date/lib/parse_date.re" { goto std; } -#line 1227 "" +#line 1238 "" yy9: YYDEBUG(9, *YYCURSOR); yych = *++YYCURSOR; @@ -1257,11 +1268,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(11, *YYCURSOR); ++YYCURSOR; YYDEBUG(12, *YYCURSOR); -#line 1959 "ext/date/lib/parse_date.re" +#line 1970 "ext/date/lib/parse_date.re" { goto std; } -#line 1265 "" +#line 1276 "" yy13: YYDEBUG(13, *YYCURSOR); yyaccept = 1; @@ -1762,7 +1773,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy20: YYDEBUG(20, *YYCURSOR); -#line 1874 "ext/date/lib/parse_date.re" +#line 1885 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("tzcorrection | tz"); @@ -1776,7 +1787,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIMEZONE; } -#line 1780 "" +#line 1791 "" yy21: YYDEBUG(21, *YYCURSOR); yych = *++YYCURSOR; @@ -3581,7 +3592,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy81: YYDEBUG(81, *YYCURSOR); -#line 1621 "ext/date/lib/parse_date.re" +#line 1632 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenoyearrev"); TIMELIB_INIT; @@ -3592,7 +3603,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 3596 "" +#line 3607 "" yy82: YYDEBUG(82, *YYCURSOR); yych = *++YYCURSOR; @@ -4107,7 +4118,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } if (yych == '.') goto yy289; YYDEBUG(114, *YYCURSOR); -#line 1196 "ext/date/lib/parse_date.re" +#line 1207 "ext/date/lib/parse_date.re" { timelib_ull i; @@ -4132,7 +4143,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 4136 "" +#line 4147 "" yy115: YYDEBUG(115, *YYCURSOR); ++YYCURSOR; @@ -5858,7 +5869,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy177: YYDEBUG(177, *YYCURSOR); -#line 1362 "ext/date/lib/parse_date.re" +#line 1373 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("timetiny24 | timeshort24 | timelong24 | iso8601long"); @@ -5885,7 +5896,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 5889 "" +#line 5900 "" yy178: YYDEBUG(178, *YYCURSOR); yyaccept = 4; @@ -6914,7 +6925,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy224: YYDEBUG(224, *YYCURSOR); -#line 1456 "ext/date/lib/parse_date.re" +#line 1467 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("americanshort | american"); @@ -6929,7 +6940,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AMERICAN; } -#line 6933 "" +#line 6944 "" yy225: YYDEBUG(225, *YYCURSOR); yyaccept = 5; @@ -7172,7 +7183,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy431; yy251: YYDEBUG(251, *YYCURSOR); -#line 1538 "ext/date/lib/parse_date.re" +#line 1549 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datefull"); @@ -7186,7 +7197,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL; } -#line 7190 "" +#line 7201 "" yy252: YYDEBUG(252, *YYCURSOR); yyaccept = 3; @@ -7300,7 +7311,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == 'e') goto yy440; yy260: YYDEBUG(260, *YYCURSOR); -#line 1943 "ext/date/lib/parse_date.re" +#line 1954 "ext/date/lib/parse_date.re" { timelib_ull i; DEBUG_OUTPUT("relative"); @@ -7315,7 +7326,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 7319 "" +#line 7330 "" yy261: YYDEBUG(261, *YYCURSOR); yych = *++YYCURSOR; @@ -7761,7 +7772,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy471; yy290: YYDEBUG(290, *YYCURSOR); -#line 1222 "ext/date/lib/parse_date.re" +#line 1233 "ext/date/lib/parse_date.re" { timelib_sll i; timelib_ull us; @@ -7800,7 +7811,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 7804 "" +#line 7815 "" yy291: YYDEBUG(291, *YYCURSOR); yych = *++YYCURSOR; @@ -7825,7 +7836,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy293: YYDEBUG(293, *YYCURSOR); -#line 1784 "ext/date/lib/parse_date.re" +#line 1795 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("ago"); TIMELIB_INIT; @@ -7845,7 +7856,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AGO; } -#line 7849 "" +#line 7860 "" yy294: YYDEBUG(294, *YYCURSOR); yyaccept = 7; @@ -7884,7 +7895,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy295: YYDEBUG(295, *YYCURSOR); -#line 1864 "ext/date/lib/parse_date.re" +#line 1875 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("monthtext"); TIMELIB_INIT; @@ -7893,7 +7904,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 7897 "" +#line 7908 "" yy296: YYDEBUG(296, *YYCURSOR); yyaccept = 7; @@ -8468,7 +8479,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy315: YYDEBUG(315, *YYCURSOR); -#line 1805 "ext/date/lib/parse_date.re" +#line 1816 "ext/date/lib/parse_date.re" { const timelib_relunit* relunit; DEBUG_OUTPUT("daytext"); @@ -8485,7 +8496,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEKDAY; } -#line 8489 "" +#line 8500 "" yy316: YYDEBUG(316, *YYCURSOR); yych = *++YYCURSOR; @@ -8753,7 +8764,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy325: YYDEBUG(325, *YYCURSOR); -#line 1607 "ext/date/lib/parse_date.re" +#line 1618 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datetextual | datenoyear"); @@ -8766,7 +8777,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 8770 "" +#line 8781 "" yy326: YYDEBUG(326, *YYCURSOR); yyaccept = 10; @@ -9460,7 +9471,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy351: YYDEBUG(351, *YYCURSOR); -#line 1153 "ext/date/lib/parse_date.re" +#line 1164 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("now"); TIMELIB_INIT; @@ -9468,7 +9479,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 9472 "" +#line 9483 "" yy352: YYDEBUG(352, *YYCURSOR); yyaccept = 2; @@ -10971,7 +10982,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy420: YYDEBUG(420, *YYCURSOR); -#line 1390 "ext/date/lib/parse_date.re" +#line 1401 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("gnunocolon"); TIMELIB_INIT; @@ -10993,7 +11004,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_GNU_NOCOLON; } -#line 10997 "" +#line 11008 "" yy421: YYDEBUG(421, *YYCURSOR); yyaccept = 13; @@ -11074,7 +11085,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy422: YYDEBUG(422, *YYCURSOR); -#line 1775 "ext/date/lib/parse_date.re" +#line 1786 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("year4"); TIMELIB_INIT; @@ -11082,7 +11093,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 11086 "" +#line 11097 "" yy423: YYDEBUG(423, *YYCURSOR); yyaccept = 3; @@ -11689,7 +11700,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(456, *YYCURSOR); ++YYCURSOR; YYDEBUG(457, *YYCURSOR); -#line 1324 "ext/date/lib/parse_date.re" +#line 1335 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12"); TIMELIB_INIT; @@ -11706,7 +11717,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME12; } -#line 11710 "" +#line 11721 "" yy458: YYDEBUG(458, *YYCURSOR); yych = *++YYCURSOR; @@ -13033,7 +13044,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy526: YYDEBUG(526, *YYCURSOR); -#line 1162 "ext/date/lib/parse_date.re" +#line 1173 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("noon"); TIMELIB_INIT; @@ -13044,7 +13055,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 13048 "" +#line 13059 "" yy527: YYDEBUG(527, *YYCURSOR); yyaccept = 2; @@ -14090,7 +14101,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy567: YYDEBUG(567, *YYCURSOR); -#line 1524 "ext/date/lib/parse_date.re" +#line 1535 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshort"); @@ -14103,7 +14114,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 14107 "" +#line 14118 "" yy568: YYDEBUG(568, *YYCURSOR); yyaccept = 15; @@ -14554,7 +14565,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy600: YYDEBUG(600, *YYCURSOR); -#line 1593 "ext/date/lib/parse_date.re" +#line 1604 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenodayrev"); @@ -14567,7 +14578,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 14571 "" +#line 14582 "" yy601: YYDEBUG(601, *YYCURSOR); yych = *++YYCURSOR; @@ -15942,7 +15953,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(696, *YYCURSOR); ++YYCURSOR; YYDEBUG(697, *YYCURSOR); -#line 1579 "ext/date/lib/parse_date.re" +#line 1590 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenoday"); @@ -15955,7 +15966,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 15959 "" +#line 15970 "" yy698: YYDEBUG(698, *YYCURSOR); yych = *++YYCURSOR; @@ -16516,7 +16527,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy722: YYDEBUG(722, *YYCURSOR); -#line 1174 "ext/date/lib/parse_date.re" +#line 1185 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("midnight | today"); TIMELIB_INIT; @@ -16525,7 +16536,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 16529 "" +#line 16540 "" yy723: YYDEBUG(723, *YYCURSOR); yych = *++YYCURSOR; @@ -16835,7 +16846,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy897; yy739: YYDEBUG(739, *YYCURSOR); -#line 1565 "ext/date/lib/parse_date.re" +#line 1576 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pointed date YY"); @@ -16848,7 +16859,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 16852 "" +#line 16863 "" yy740: YYDEBUG(740, *YYCURSOR); yyaccept = 15; @@ -16960,7 +16971,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy752: YYDEBUG(752, *YYCURSOR); -#line 1510 "ext/date/lib/parse_date.re" +#line 1521 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshorter"); @@ -16973,7 +16984,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 16977 "" +#line 16988 "" yy753: YYDEBUG(753, *YYCURSOR); yyaccept = 18; @@ -17222,7 +17233,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy777: YYDEBUG(777, *YYCURSOR); -#line 1436 "ext/date/lib/parse_date.re" +#line 1447 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("iso8601nocolon"); @@ -17241,7 +17252,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_NOCOLON; } -#line 17245 "" +#line 17256 "" yy778: YYDEBUG(778, *YYCURSOR); yyaccept = 19; @@ -18469,7 +18480,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy849: YYDEBUG(849, *YYCURSOR); -#line 1913 "ext/date/lib/parse_date.re" +#line 1924 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz"); @@ -18498,7 +18509,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 18502 "" +#line 18513 "" yy850: YYDEBUG(850, *YYCURSOR); yyaccept = 20; @@ -19542,7 +19553,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy926: YYDEBUG(926, *YYCURSOR); -#line 1671 "ext/date/lib/parse_date.re" +#line 1682 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgydotd"); @@ -19555,7 +19566,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_YEARDAY; } -#line 19559 "" +#line 19570 "" yy927: YYDEBUG(927, *YYCURSOR); yyaccept = 21; @@ -19809,7 +19820,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '7') goto yy1059; yy942: YYDEBUG(942, *YYCURSOR); -#line 1704 "ext/date/lib/parse_date.re" +#line 1715 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweek"); @@ -19827,7 +19838,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 19831 "" +#line 19842 "" yy943: YYDEBUG(943, *YYCURSOR); yych = *++YYCURSOR; @@ -20303,7 +20314,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == 'e') goto yy1094; yy982: YYDEBUG(982, *YYCURSOR); -#line 1847 "ext/date/lib/parse_date.re" +#line 1858 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -20319,7 +20330,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 20323 "" +#line 20334 "" yy983: YYDEBUG(983, *YYCURSOR); yych = *++YYCURSOR; @@ -20666,7 +20677,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1020, *YYCURSOR); ++YYCURSOR; YYDEBUG(1021, *YYCURSOR); -#line 1553 "ext/date/lib/parse_date.re" +#line 1564 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("pointed date YYYY"); TIMELIB_INIT; @@ -20677,7 +20688,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 20681 "" +#line 20692 "" yy1022: YYDEBUG(1022, *YYCURSOR); ++YYCURSOR; @@ -20706,7 +20717,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1025: YYDEBUG(1025, *YYCURSOR); -#line 1484 "ext/date/lib/parse_date.re" +#line 1495 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("iso8601date2"); @@ -20719,7 +20730,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 20723 "" +#line 20734 "" yy1026: YYDEBUG(1026, *YYCURSOR); yyaccept = 15; @@ -20939,7 +20950,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1043: YYDEBUG(1043, *YYCURSOR); -#line 1472 "ext/date/lib/parse_date.re" +#line 1483 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | dateslash"); TIMELIB_INIT; @@ -20950,7 +20961,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 20954 "" +#line 20965 "" yy1044: YYDEBUG(1044, *YYCURSOR); yyaccept = 26; @@ -21065,7 +21076,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1048: YYDEBUG(1048, *YYCURSOR); -#line 1633 "ext/date/lib/parse_date.re" +#line 1644 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenocolon"); TIMELIB_INIT; @@ -21076,7 +21087,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NOCOLON; } -#line 21080 "" +#line 21091 "" yy1049: YYDEBUG(1049, *YYCURSOR); yych = *++YYCURSOR; @@ -21146,7 +21157,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1059, *YYCURSOR); ++YYCURSOR; YYDEBUG(1060, *YYCURSOR); -#line 1685 "ext/date/lib/parse_date.re" +#line 1696 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweekday"); @@ -21164,7 +21175,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 21168 "" +#line 21179 "" yy1061: YYDEBUG(1061, *YYCURSOR); yych = *++YYCURSOR; @@ -21227,7 +21238,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1143; yy1070: YYDEBUG(1070, *YYCURSOR); -#line 1723 "ext/date/lib/parse_date.re" +#line 1734 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextshort"); @@ -21240,7 +21251,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 21244 "" +#line 21255 "" yy1071: YYDEBUG(1071, *YYCURSOR); yych = *++YYCURSOR; @@ -21713,7 +21724,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1107: YYDEBUG(1107, *YYCURSOR); -#line 1184 "ext/date/lib/parse_date.re" +#line 1195 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("tomorrow"); TIMELIB_INIT; @@ -21724,7 +21735,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 21728 "" +#line 21739 "" yy1108: YYDEBUG(1108, *YYCURSOR); yyaccept = 28; @@ -22061,7 +22072,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1140, *YYCURSOR); ++YYCURSOR; YYDEBUG(1141, *YYCURSOR); -#line 1737 "ext/date/lib/parse_date.re" +#line 1748 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextreverse"); @@ -22074,7 +22085,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 22078 "" +#line 22089 "" yy1142: YYDEBUG(1142, *YYCURSOR); ++YYCURSOR; @@ -22118,7 +22129,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1145: YYDEBUG(1145, *YYCURSOR); -#line 1279 "ext/date/lib/parse_date.re" +#line 1290 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("backof | frontof"); TIMELIB_INIT; @@ -22140,7 +22151,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 22144 "" +#line 22155 "" yy1146: YYDEBUG(1146, *YYCURSOR); yyaccept = 29; @@ -22464,7 +22475,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1172: YYDEBUG(1172, *YYCURSOR); -#line 1823 "ext/date/lib/parse_date.re" +#line 1834 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -22487,7 +22498,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22491 "" +#line 22502 "" yy1173: YYDEBUG(1173, *YYCURSOR); yych = *++YYCURSOR; @@ -22499,7 +22510,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1175: YYDEBUG(1175, *YYCURSOR); -#line 1141 "ext/date/lib/parse_date.re" +#line 1152 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("yesterday"); TIMELIB_INIT; @@ -22510,7 +22521,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22514 "" +#line 22525 "" yy1176: YYDEBUG(1176, *YYCURSOR); yyaccept = 31; @@ -23003,7 +23014,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1222, *YYCURSOR); ++YYCURSOR; YYDEBUG(1223, *YYCURSOR); -#line 1889 "ext/date/lib/parse_date.re" +#line 1900 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("dateshortwithtimeshort12 | dateshortwithtimelong12"); TIMELIB_INIT; @@ -23026,7 +23037,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 23030 "" +#line 23041 "" yy1224: YYDEBUG(1224, *YYCURSOR); yych = *++YYCURSOR; @@ -23528,7 +23539,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1268, *YYCURSOR); ++YYCURSOR; YYDEBUG(1269, *YYCURSOR); -#line 1302 "ext/date/lib/parse_date.re" +#line 1313 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -23549,7 +23560,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEK_DAY_OF_MONTH; } -#line 23553 "" +#line 23564 "" yy1270: YYDEBUG(1270, *YYCURSOR); yyaccept = 24; @@ -23596,7 +23607,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1273, *YYCURSOR); ++YYCURSOR; YYDEBUG(1274, *YYCURSOR); -#line 1262 "ext/date/lib/parse_date.re" +#line 1273 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("firstdayof | lastdayof"); TIMELIB_INIT; @@ -23612,12 +23623,12 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 23616 "" +#line 23627 "" yy1275: YYDEBUG(1275, *YYCURSOR); ++YYCURSOR; YYDEBUG(1276, *YYCURSOR); -#line 1498 "ext/date/lib/parse_date.re" +#line 1509 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601datex"); TIMELIB_INIT; @@ -23628,7 +23639,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 23632 "" +#line 23643 "" yy1277: YYDEBUG(1277, *YYCURSOR); yych = *++YYCURSOR; @@ -23731,7 +23742,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1290, *YYCURSOR); ++YYCURSOR; YYDEBUG(1291, *YYCURSOR); -#line 1342 "ext/date/lib/parse_date.re" +#line 1353 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("mssqltime"); TIMELIB_INIT; @@ -23750,7 +23761,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 23754 "" +#line 23765 "" yy1292: YYDEBUG(1292, *YYCURSOR); yych = *++YYCURSOR; @@ -24174,7 +24185,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1331; yy1329: YYDEBUG(1329, *YYCURSOR); -#line 1645 "ext/date/lib/parse_date.re" +#line 1656 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif"); @@ -24199,7 +24210,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_XMLRPC_SOAP; } -#line 24203 "" +#line 24214 "" yy1330: YYDEBUG(1330, *YYCURSOR); yych = *++YYCURSOR; @@ -24569,7 +24580,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= ':') goto yy1383; yy1375: YYDEBUG(1375, *YYCURSOR); -#line 1751 "ext/date/lib/parse_date.re" +#line 1762 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("clf"); @@ -24592,7 +24603,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 24596 "" +#line 24607 "" yy1376: YYDEBUG(1376, *YYCURSOR); yyaccept = 33; @@ -24824,7 +24835,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == ':') goto yy1286; goto yy1329; } -#line 1979 "ext/date/lib/parse_date.re" +#line 1990 "ext/date/lib/parse_date.re" } diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re index 3159ff7fa8cac..5d259ed4e2c75 100644 --- a/ext/date/lib/parse_date.re +++ b/ext/date/lib/parse_date.re @@ -711,6 +711,17 @@ static const timelib_relunit* timelib_lookup_relunit(const char **ptr) return value; } +static void add_with_overflow(Scanner *s, timelib_sll *e, timelib_sll amount, int multiplier) +{ +#if defined(__has_builtin) && __has_builtin(__builtin_saddll_overflow) + if (__builtin_saddll_overflow(*e, amount * multiplier, e)) { + add_error(s, TIMELIB_ERR_NUMBER_OUT_OF_RANGE, "Number out of range"); + } +#else + *e += (amount * multiplier); +#endif +} + /** * The time_part parameter is a flag. It can be TIMELIB_TIME_PART_KEEP in case * the time portion should not be reset to midnight, or @@ -726,13 +737,13 @@ static void timelib_set_relative(const char **ptr, timelib_sll amount, int behav } switch (relunit->unit) { - case TIMELIB_MICROSEC: s->time->relative.us += amount * relunit->multiplier; break; - case TIMELIB_SECOND: s->time->relative.s += amount * relunit->multiplier; break; - case TIMELIB_MINUTE: s->time->relative.i += amount * relunit->multiplier; break; - case TIMELIB_HOUR: s->time->relative.h += amount * relunit->multiplier; break; - case TIMELIB_DAY: s->time->relative.d += amount * relunit->multiplier; break; - case TIMELIB_MONTH: s->time->relative.m += amount * relunit->multiplier; break; - case TIMELIB_YEAR: s->time->relative.y += amount * relunit->multiplier; break; + case TIMELIB_MICROSEC: add_with_overflow(s, &s->time->relative.us, amount, relunit->multiplier); break; + case TIMELIB_SECOND: add_with_overflow(s, &s->time->relative.s, amount, relunit->multiplier); break; + case TIMELIB_MINUTE: add_with_overflow(s, &s->time->relative.i, amount, relunit->multiplier); break; + case TIMELIB_HOUR: add_with_overflow(s, &s->time->relative.h, amount, relunit->multiplier); break; + case TIMELIB_DAY: add_with_overflow(s, &s->time->relative.d, amount, relunit->multiplier); break; + case TIMELIB_MONTH: add_with_overflow(s, &s->time->relative.m, amount, relunit->multiplier); break; + case TIMELIB_YEAR: add_with_overflow(s, &s->time->relative.y, amount, relunit->multiplier); break; case TIMELIB_WEEKDAY: TIMELIB_HAVE_WEEKDAY_RELATIVE(); diff --git a/ext/date/lib/timelib.c b/ext/date/lib/timelib.c index d42c69bbd6f06..6473a2798a80e 100644 --- a/ext/date/lib/timelib.c +++ b/ext/date/lib/timelib.c @@ -187,14 +187,22 @@ timelib_long timelib_date_to_int(timelib_time *d, int *error) void timelib_decimal_hour_to_hms(double h, int *hour, int *min, int *sec) { - if (h > 0) { - *hour = floor(h); - *min = floor((h - *hour) * 60); - *sec = (h - *hour - ((float) *min / 60)) * 3600; - } else { - *hour = ceil(h); - *min = 0 - ceil((h - *hour) * 60); - *sec = 0 - (h - *hour - ((float) *min / -60)) * 3600; + bool swap = false; + int seconds; + + if (h < 0) { + swap = true; + h = fabs(h); + } + + *hour = floor(h); + seconds = floor((h - *hour) * 3600); + + *min = seconds / 60; + *sec = seconds % 60; + + if (swap) { + *hour = 0 - *hour; } } diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index a532bf60356c7..4582fcfd46917 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -30,9 +30,9 @@ # include "timelib_config.h" #endif -#define TIMELIB_VERSION 202209 -#define TIMELIB_EXTENDED_VERSION 20220901 -#define TIMELIB_ASCII_VERSION "2022.09" +#define TIMELIB_VERSION 202210 +#define TIMELIB_EXTENDED_VERSION 20221001 +#define TIMELIB_ASCII_VERSION "2022.10" #include #include diff --git a/ext/dom/document.c b/ext/dom/document.c index 59f00897a69aa..8312d6c59399f 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -23,6 +23,7 @@ #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "php_dom.h" #include +#include #ifdef LIBXML_SCHEMAS_ENABLED #include #include diff --git a/ext/dom/element.c b/ext/dom/element.c index c630bec2b5007..f5733c5c48bf3 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -724,6 +724,83 @@ PHP_METHOD(DOMElement, setAttributeNS) } /* }}} end dom_element_set_attribute_ns */ +static void dom_remove_eliminated_ns_single_element(xmlNodePtr node, xmlNsPtr eliminatedNs) +{ + ZEND_ASSERT(node->type == XML_ELEMENT_NODE); + if (node->ns == eliminatedNs) { + node->ns = NULL; + } + + for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) { + if (attr->ns == eliminatedNs) { + attr->ns = NULL; + } + } +} + +static void dom_remove_eliminated_ns(xmlNodePtr node, xmlNsPtr eliminatedNs) +{ + dom_remove_eliminated_ns_single_element(node, eliminatedNs); + + xmlNodePtr base = node; + node = node->children; + while (node != NULL) { + ZEND_ASSERT(node != base); + + if (node->type == XML_ELEMENT_NODE) { + dom_remove_eliminated_ns_single_element(node, eliminatedNs); + + if (node->children) { + node = node->children; + continue; + } + } + + if (node->next) { + node = node->next; + } else { + /* Go upwards, until we find a parent node with a next sibling, or until we hit the base. */ + do { + node = node->parent; + if (node == base) { + return; + } + } while (node->next == NULL); + node = node->next; + } + } +} + +static void dom_eliminate_ns(xmlNodePtr nodep, xmlNsPtr nsptr) +{ + if (nsptr->href != NULL) { + xmlFree((char *) nsptr->href); + nsptr->href = NULL; + } + if (nsptr->prefix != NULL) { + xmlFree((char *) nsptr->prefix); + nsptr->prefix = NULL; + } + + /* Remove it from the list and move it to the old ns list */ + xmlNsPtr current_ns = nodep->nsDef; + if (current_ns == nsptr) { + nodep->nsDef = nsptr->next; + } else { + do { + if (current_ns->next == nsptr) { + current_ns->next = nsptr->next; + break; + } + current_ns = current_ns->next; + } while (current_ns != NULL); + } + nsptr->next = NULL; + dom_set_old_ns(nodep->doc, nsptr); + + dom_remove_eliminated_ns(nodep, nsptr); +} + /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElRemAtNS Since: DOM Level 2 */ @@ -754,14 +831,7 @@ PHP_METHOD(DOMElement, removeAttributeNS) nsptr = dom_get_nsdecl(nodep, (xmlChar *)name); if (nsptr != NULL) { if (xmlStrEqual((xmlChar *)uri, nsptr->href)) { - if (nsptr->href != NULL) { - xmlFree((char *) nsptr->href); - nsptr->href = NULL; - } - if (nsptr->prefix != NULL) { - xmlFree((char *) nsptr->prefix); - nsptr->prefix = NULL; - } + dom_eliminate_ns(nodep, nsptr); } else { RETURN_NULL(); } diff --git a/ext/dom/tests/DOMDocument_loadXML_error1.phpt b/ext/dom/tests/DOMDocument_loadXML_error1.phpt index 14d99e4ed9ad9..2af3217bd6c6a 100644 --- a/ext/dom/tests/DOMDocument_loadXML_error1.phpt +++ b/ext/dom/tests/DOMDocument_loadXML_error1.phpt @@ -1,5 +1,9 @@ --TEST-- Test DOMDocument::loadXML() detects not-well formed XML +--SKIPIF-- += 21200) die('skip libxml2 test variant for version < 2.12'); +?> --DESCRIPTION-- This test verifies the method detects an opening and ending tag mismatch Environment variables used in the test: diff --git a/ext/dom/tests/DOMDocument_loadXML_error1_gte2_12.phpt b/ext/dom/tests/DOMDocument_loadXML_error1_gte2_12.phpt new file mode 100644 index 0000000000000..e1ded0ffadd7f --- /dev/null +++ b/ext/dom/tests/DOMDocument_loadXML_error1_gte2_12.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test DOMDocument::loadXML() detects not-well formed XML +--SKIPIF-- += 2.12'); +?> +--DESCRIPTION-- +This test verifies the method detects an opening and ending tag mismatch +Environment variables used in the test: +- XML_FILE: the xml file to load +- LOAD_OPTIONS: the second parameter to pass to the method +- EXPECTED_RESULT: the expected result +--CREDITS-- +Antonio Diaz Ruiz +--EXTENSIONS-- +dom +--ENV-- +XML_FILE=/not_well_formed.xml +LOAD_OPTIONS=0 +EXPECTED_RESULT=0 +--FILE_EXTERNAL-- +domdocumentloadxml_test_method.inc +--EXPECTF-- +Warning: DOMDocument::load%r(XML){0,1}%r(): Opening and ending tag mismatch: title line 5 and book %s + +Warning: DOMDocument::load%r(XML){0,1}%r(): %rexpected '>'|Opening and ending tag mismatch: book line (4|5) and books%r %s diff --git a/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt index ff5ceb3fbed53..f52d3348138c5 100644 --- a/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt +++ b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt @@ -2,7 +2,7 @@ Test DOMDocument::loadXML() detects not-well formed XML --SKIPIF-- = 2.11'); +if (LIBXML_VERSION < 21100 || LIBXML_VERSION >= 21200) die('skip libxml2 test variant for version >= 2.11 && <= 2.12'); ?> --DESCRIPTION-- This test verifies the method detects attributes values not closed between " or ' diff --git a/ext/dom/tests/DOMDocument_loadXML_error2_gte2_12.phpt b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_12.phpt new file mode 100644 index 0000000000000..6a3ff5841f565 --- /dev/null +++ b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_12.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test DOMDocument::loadXML() detects not-well formed XML +--SKIPIF-- += 2.12'); +?> +--DESCRIPTION-- +This test verifies the method detects attributes values not closed between " or ' +Environment variables used in the test: +- XML_FILE: the xml file to load +- LOAD_OPTIONS: the second parameter to pass to the method +- EXPECTED_RESULT: the expected result +--CREDITS-- +Antonio Diaz Ruiz +--EXTENSIONS-- +dom +--ENV-- +XML_FILE=/not_well_formed2.xml +LOAD_OPTIONS=0 +EXPECTED_RESULT=0 +--FILE_EXTERNAL-- +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(): Couldn't find end of Start Tag book line 4 in Entity, line: 4 in %s on line %d + +Warning: DOMDocument::loadXML(): Opening and ending tag mismatch: books line 3 and book in Entity, line: 7 in %s on line %d diff --git a/ext/dom/tests/DOMDocument_load_error1.phpt b/ext/dom/tests/DOMDocument_load_error1.phpt index f736b0a0e81c6..2da8c0cd18b4e 100644 --- a/ext/dom/tests/DOMDocument_load_error1.phpt +++ b/ext/dom/tests/DOMDocument_load_error1.phpt @@ -1,5 +1,9 @@ --TEST-- Test DOMDocument::load() detects not-well formed XML +--SKIPIF-- += 21200) die('skip libxml2 test variant for version < 2.12'); +?> --DESCRIPTION-- This test verifies the method detects an opening and ending tag mismatch Environment variables used in the test: diff --git a/ext/dom/tests/DOMDocument_load_error1_gte2_12.phpt b/ext/dom/tests/DOMDocument_load_error1_gte2_12.phpt new file mode 100644 index 0000000000000..183c8406fdfc8 --- /dev/null +++ b/ext/dom/tests/DOMDocument_load_error1_gte2_12.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test DOMDocument::load() detects not-well formed XML +--SKIPIF-- += 2.12'); +?> +--DESCRIPTION-- +This test verifies the method detects an opening and ending tag mismatch +Environment variables used in the test: +- XML_FILE: the xml file to load +- LOAD_OPTIONS: the second parameter to pass to the method +- EXPECTED_RESULT: the expected result +--CREDITS-- +Antonio Diaz Ruiz +--EXTENSIONS-- +dom +--ENV-- +XML_FILE=/not_well_formed.xml +LOAD_OPTIONS=0 +EXPECTED_RESULT=0 +--FILE_EXTERNAL-- +domdocumentload_test_method.inc +--EXPECTF-- +Warning: DOMDocument::load%r(XML){0,1}%r(): Opening and ending tag mismatch: title line 5 and book %s + +Warning: DOMDocument::load%r(XML){0,1}%r(): %rexpected '>'|Opening and ending tag mismatch: book line (4|5) and books%r %s diff --git a/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt b/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt index 32b6bf161142e..4d9f992b3bafd 100644 --- a/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt +++ b/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt @@ -2,7 +2,7 @@ Test DOMDocument::load() detects not-well formed --SKIPIF-- = 2.11'); +if (LIBXML_VERSION < 21100 || LIBXML_VERSION >= 21200) die('skip libxml2 test variant for version >= 2.11 && <= 2.12'); ?> --DESCRIPTION-- This test verifies the method detects attributes values not closed between " or ' diff --git a/ext/dom/tests/DOMDocument_load_error2_gte2_12.phpt b/ext/dom/tests/DOMDocument_load_error2_gte2_12.phpt new file mode 100644 index 0000000000000..4fadf41736124 --- /dev/null +++ b/ext/dom/tests/DOMDocument_load_error2_gte2_12.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test DOMDocument::load() detects not-well formed +--SKIPIF-- += 2.12'); +?> +--DESCRIPTION-- +This test verifies the method detects attributes values not closed between " or ' +Environment variables used in the test: +- XML_FILE: the xml file to load +- LOAD_OPTIONS: the second parameter to pass to the method +- EXPECTED_RESULT: the expected result +--CREDITS-- +Antonio Diaz Ruiz +--EXTENSIONS-- +dom +--ENV-- +XML_FILE=/not_well_formed2.xml +LOAD_OPTIONS=0 +EXPECTED_RESULT=0 +--FILE_EXTERNAL-- +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(): Couldn't find end of Start Tag book line 4 in %s on line %d + +Warning: DOMDocument::load(): Opening and ending tag mismatch: books line 3 and book in %s on line %d diff --git a/ext/dom/tests/gh12616_1.phpt b/ext/dom/tests/gh12616_1.phpt new file mode 100644 index 0000000000000..408d871aee6f6 --- /dev/null +++ b/ext/dom/tests/gh12616_1.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-12616 (DOM: Removing XMLNS namespace node results in invalid default: prefix) +--EXTENSIONS-- +dom +--FILE-- +loadXML( + << + CHILDREN + + XML +); + +$doc->documentElement->removeAttributeNS('http://symfony.com/schema/dic/services', ''); +echo $doc->saveXML(); + +$new = new DOMDocument(); +$new->append( + $new->importNode($doc->documentElement, true) +); + +echo $new->saveXML(); + +?> +--EXPECT-- + + + CHILDREN + + + + CHILDREN + diff --git a/ext/dom/tests/gh12616_2.phpt b/ext/dom/tests/gh12616_2.phpt new file mode 100644 index 0000000000000..57138e4c45b3f --- /dev/null +++ b/ext/dom/tests/gh12616_2.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-12616 (DOM: Removing XMLNS namespace node results in invalid default: prefix) +--EXTENSIONS-- +dom +--FILE-- +loadXML( + << + + + + + XML +); + +$doc->documentElement->removeAttributeNS('http://symfony.com/schema/dic/services', 'symfony'); +$xpath = new DOMXPath($doc); +$xpath->registerNamespace('test', 'urn:test'); + +echo $doc->saveXML(); + +$result = $xpath->query('//container/services/test:service[@id="hello"]'); +var_dump($result); + +?> +--EXPECT-- + + + + + + +object(DOMNodeList)#4 (1) { + ["length"]=> + int(1) +} diff --git a/ext/dom/tests/gh12616_3.phpt b/ext/dom/tests/gh12616_3.phpt new file mode 100644 index 0000000000000..871a5e4607a30 --- /dev/null +++ b/ext/dom/tests/gh12616_3.phpt @@ -0,0 +1,152 @@ +--TEST-- +GH-12616 (DOM: Removing XMLNS namespace node results in invalid default: prefix) +--EXTENSIONS-- +dom +--FILE-- +loadXML( + << + + + + + + + + + + XML +); + +$doc->documentElement->firstElementChild->removeAttributeNS('http://symfony.com/schema/dic/services', 'x'); +echo $doc->saveXML(); + +$xpath = new DOMXPath($doc); + +echo "--- Namespaces of child1 ---\n"; + +foreach ($xpath->query("/container/child1/namespace::*") as $ns) { + var_dump($ns); +} + +echo "--- Namespaces of child1/foo (both nodes) ---\n"; + +foreach ($xpath->query("/container/child1/foo/namespace::*") as $ns) { + var_dump($ns); +} + +echo "--- Namespaces of child2 ---\n"; + +foreach ($xpath->query("/container/child2/namespace::*") as $ns) { + var_dump($ns); +} + +?> +--EXPECT-- + + + + + + + + + + + +--- Namespaces of child1 --- +object(DOMNameSpaceNode)#4 (8) { + ["nodeName"]=> + string(9) "xmlns:xml" + ["nodeValue"]=> + string(36) "http://www.w3.org/XML/1998/namespace" + ["nodeType"]=> + int(18) + ["prefix"]=> + string(3) "xml" + ["localName"]=> + string(3) "xml" + ["namespaceURI"]=> + string(36) "http://www.w3.org/XML/1998/namespace" + ["ownerDocument"]=> + string(22) "(object value omitted)" + ["parentNode"]=> + string(22) "(object value omitted)" +} +--- Namespaces of child1/foo (both nodes) --- +object(DOMNameSpaceNode)#5 (8) { + ["nodeName"]=> + string(9) "xmlns:xml" + ["nodeValue"]=> + string(36) "http://www.w3.org/XML/1998/namespace" + ["nodeType"]=> + int(18) + ["prefix"]=> + string(3) "xml" + ["localName"]=> + string(3) "xml" + ["namespaceURI"]=> + string(36) "http://www.w3.org/XML/1998/namespace" + ["ownerDocument"]=> + string(22) "(object value omitted)" + ["parentNode"]=> + string(22) "(object value omitted)" +} +object(DOMNameSpaceNode)#8 (8) { + ["nodeName"]=> + string(9) "xmlns:xml" + ["nodeValue"]=> + string(36) "http://www.w3.org/XML/1998/namespace" + ["nodeType"]=> + int(18) + ["prefix"]=> + string(3) "xml" + ["localName"]=> + string(3) "xml" + ["namespaceURI"]=> + string(36) "http://www.w3.org/XML/1998/namespace" + ["ownerDocument"]=> + string(22) "(object value omitted)" + ["parentNode"]=> + string(22) "(object value omitted)" +} +--- Namespaces of child2 --- +object(DOMNameSpaceNode)#9 (8) { + ["nodeName"]=> + string(9) "xmlns:xml" + ["nodeValue"]=> + string(36) "http://www.w3.org/XML/1998/namespace" + ["nodeType"]=> + int(18) + ["prefix"]=> + string(3) "xml" + ["localName"]=> + string(3) "xml" + ["namespaceURI"]=> + string(36) "http://www.w3.org/XML/1998/namespace" + ["ownerDocument"]=> + string(22) "(object value omitted)" + ["parentNode"]=> + string(22) "(object value omitted)" +} +object(DOMNameSpaceNode)#5 (8) { + ["nodeName"]=> + string(7) "xmlns:x" + ["nodeValue"]=> + string(38) "http://symfony.com/schema/dic/services" + ["nodeType"]=> + int(18) + ["prefix"]=> + string(1) "x" + ["localName"]=> + string(1) "x" + ["namespaceURI"]=> + string(38) "http://symfony.com/schema/dic/services" + ["ownerDocument"]=> + string(22) "(object value omitted)" + ["parentNode"]=> + string(22) "(object value omitted)" +} diff --git a/ext/exif/tests/bug78793.phpt b/ext/exif/tests/bug78793.phpt index 93d728ff6d1cf..babbe927045d3 100644 --- a/ext/exif/tests/bug78793.phpt +++ b/ext/exif/tests/bug78793.phpt @@ -4,7 +4,7 @@ Bug #78793: Use-after-free in exif parsing under memory sanitizer exif --FILE-- last_ssl_session) { + SSL_SESSION_free(ftp->last_ssl_session); + } +#endif if (ftp->data) { data_close(ftp, ftp->data); } @@ -229,6 +234,22 @@ ftp_quit(ftpbuf_t *ftp) } /* }}} */ +#ifdef HAVE_FTP_SSL +static int ftp_ssl_new_session_cb(SSL *ssl, SSL_SESSION *sess) +{ + ftpbuf_t *ftp = SSL_get_app_data(ssl); + + /* Technically there can be multiple sessions per connection, but we only care about the most recent one. */ + if (ftp->last_ssl_session) { + SSL_SESSION_free(ftp->last_ssl_session); + } + ftp->last_ssl_session = SSL_get1_session(ssl); + + /* Return 0 as we are not using OpenSSL's session cache. */ + return 0; +} +#endif + /* {{{ ftp_login */ int ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pass, const size_t pass_len) @@ -279,10 +300,13 @@ ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pa #endif SSL_CTX_set_options(ctx, ssl_ctx_options); - /* allow SSL to re-use sessions */ - SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH); + /* Allow SSL to re-use sessions. + * We're relying on our own session storage as only at most one session will ever be active per FTP connection. */ + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH | SSL_SESS_CACHE_NO_INTERNAL); + SSL_CTX_sess_set_new_cb(ctx, ftp_ssl_new_session_cb); ftp->ssl_handle = SSL_new(ctx); + SSL_set_app_data(ftp->ssl_handle, ftp); /* Needed for ftp_ssl_new_session_cb */ SSL_CTX_free(ctx); if (ftp->ssl_handle == NULL) { @@ -1789,7 +1813,7 @@ data_accept(databuf_t *data, ftpbuf_t *ftp) } /* get the session from the control connection so we can re-use it */ - session = SSL_get_session(ftp->ssl_handle); + session = ftp->last_ssl_session; if (session == NULL) { php_error_docref(NULL, E_WARNING, "data_accept: failed to retrieve the existing SSL session"); SSL_free(data->ssl_handle); @@ -1797,6 +1821,7 @@ data_accept(databuf_t *data, ftpbuf_t *ftp) } /* and set it on the data connection */ + SSL_set_app_data(data->ssl_handle, ftp); /* Needed for ftp_ssl_new_session_cb */ res = SSL_set_session(data->ssl_handle, session); if (res == 0) { php_error_docref(NULL, E_WARNING, "data_accept: failed to set the existing SSL session"); diff --git a/ext/ftp/ftp.h b/ext/ftp/ftp.h index 9b50ea71ff5d5..5e96351ebdaee 100644 --- a/ext/ftp/ftp.h +++ b/ext/ftp/ftp.h @@ -82,6 +82,7 @@ typedef struct ftpbuf int old_ssl; /* old mode = forced data encryption */ SSL *ssl_handle; /* handle for control connection */ int ssl_active; /* ssl active on control conn */ + SSL_SESSION *last_ssl_session; /* last negotiated session */ #endif } ftpbuf_t; diff --git a/ext/gd/tests/bug79945.phpt b/ext/gd/tests/bug79945.phpt new file mode 100644 index 0000000000000..b985ddd48be31 --- /dev/null +++ b/ext/gd/tests/bug79945.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #79945 (using php wrappers in imagecreatefrompng causes segmentation fault) +--EXTENSIONS-- +gd +--SKIPIF-- + +--FILE-- + +--CLEAN-- +--EXPECTF-- + +Warning: imagecreatefrompng(): "php://filter/read=convert.base64-encode/resource=%s" is not a valid PNG file in %s on line %d diff --git a/ext/intl/tests/bug69398-icu74.1.phpt b/ext/intl/tests/bug69398-icu74.1.phpt new file mode 100644 index 0000000000000..cf8ce39d1e270 --- /dev/null +++ b/ext/intl/tests/bug69398-icu74.1.phpt @@ -0,0 +1,19 @@ +--TEST-- +IntlDateFormatter::formatObject(): returns wrong value when time style is NONE. +--EXTENSIONS-- +intl +--SKIPIF-- + +--FILE-- +setTime($millitimestamp); +echo IntlDateFormatter::formatObject($date, array(IntlDateFormatter::SHORT, IntlDateFormatter::NONE), 'vi_VN'), "\n"; +echo IntlDateFormatter::formatObject ($date, array(IntlDateFormatter::SHORT, IntlDateFormatter::NONE), 'ko_KR'), "\n"; +?> +--EXPECT-- +4/4/15 +15. 4. 4. diff --git a/ext/intl/tests/bug69398.phpt b/ext/intl/tests/bug69398.phpt index 02c4b7daeff9f..075dd5f4bd0c8 100644 --- a/ext/intl/tests/bug69398.phpt +++ b/ext/intl/tests/bug69398.phpt @@ -3,7 +3,10 @@ IntlDateFormatter::formatObject(): returns wrong value when time style is NONE. --EXTENSIONS-- intl --SKIPIF-- -= 51.1.2'); ?> += 0) die('skip for ICU >= 74.1'); +?> --FILE-- diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 22eb1901b8909..1de693892b7aa 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -472,7 +472,11 @@ static void _php_libxml_free_error(void *ptr) xmlResetError((xmlErrorPtr) ptr); } -static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg) +#if LIBXML_VERSION >= 21200 +static void _php_list_set_error_structure(const xmlError *error, const char *msg) +#else +static void _php_list_set_error_structure(xmlError *error, const char *msg) +#endif { xmlError error_copy; int ret; @@ -725,7 +729,11 @@ PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...) va_end(args); } +#if LIBXML_VERSION >= 21200 +PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, const xmlError *error) +#else PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error) +#endif { _php_list_set_error_structure(error, NULL); @@ -957,11 +965,9 @@ PHP_FUNCTION(libxml_use_internal_errors) /* {{{ Retrieve last error from libxml */ PHP_FUNCTION(libxml_get_last_error) { - xmlErrorPtr error; - ZEND_PARSE_PARAMETERS_NONE(); - error = xmlGetLastError(); + const xmlError *error = xmlGetLastError(); if (error) { object_init_ex(return_value, libxmlerror_class_entry); diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h index af1cc7d6ac8c5..b484568bb1b0a 100644 --- a/ext/libxml/php_libxml.h +++ b/ext/libxml/php_libxml.h @@ -35,6 +35,7 @@ extern zend_module_entry libxml_module_entry; #include "zend_smart_str.h" #include +#include #define LIBXML_SAVE_NOEMPTYTAG 1<<2 diff --git a/ext/mbstring/mbstring.stub.php b/ext/mbstring/mbstring.stub.php index 0d04e34bc7823..77d3fee67aab5 100644 --- a/ext/mbstring/mbstring.stub.php +++ b/ext/mbstring/mbstring.stub.php @@ -171,10 +171,10 @@ function mb_decode_numericentity(string $string, array $map, ?string $encoding = function mb_send_mail(string $to, string $subject, string $message, array|string $additional_headers = [], ?string $additional_params = null): bool {} /** - * @return array|string|int|false + * @return array|string|int|false|null * @refcount 1 */ -function mb_get_info(string $type = "all"): array|string|int|false {} +function mb_get_info(string $type = "all"): array|string|int|false|null {} function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool {} diff --git a/ext/mbstring/mbstring_arginfo.h b/ext/mbstring/mbstring_arginfo.h index 3bf10789e0d6c..924c6864e54dc 100644 --- a/ext/mbstring/mbstring_arginfo.h +++ b/ext/mbstring/mbstring_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0c9ac8888b8332557f7098cfb9d259757af8b3c6 */ + * Stub hash: 131af756402aecb88d2265f2a3d25aa5c66a7185 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mb_language, 0, 0, MAY_BE_STRING|MAY_BE_BOOL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, language, IS_STRING, 1, "null") @@ -177,7 +177,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mb_send_mail, 0, 3, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, additional_params, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mb_get_info, 0, 0, MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_LONG|MAY_BE_FALSE) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mb_get_info, 0, 0, MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, type, IS_STRING, 0, "\"all\"") ZEND_END_ARG_INFO() diff --git a/ext/mbstring/tests/mb_get_info_http_input.phpt b/ext/mbstring/tests/mb_get_info_http_input.phpt new file mode 100644 index 0000000000000..5cfac7a833679 --- /dev/null +++ b/ext/mbstring/tests/mb_get_info_http_input.phpt @@ -0,0 +1,10 @@ +--TEST-- +mb_get_info("http_input") can return null +--EXTENSIONS-- +mbstring +--FILE-- + +--EXPECT-- +NULL diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index 923b2049914e9..0331518d7d3d6 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -346,8 +346,8 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s) } MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic); } + PACKET_FREE(&fields_eof); } while (0); - PACKET_FREE(&fields_eof); break; /* switch break */ } } while (0); @@ -735,8 +735,8 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const c UPSERT_STATUS_GET_SERVER_STATUS(conn->upsert_status)); free_end: PACKET_FREE(&row_packet); + DBG_INF_FMT("rows=%llu", (unsigned long long)set->row_count); end: - DBG_INF_FMT("rows=%llu", (unsigned long long)result->stored_data->row_count); DBG_RETURN(ret); } /* }}} */ diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4 index 2a83fa2455974..0b923206282c4 100644 --- a/ext/opcache/config.m4 +++ b/ext/opcache/config.m4 @@ -29,7 +29,7 @@ if test "$PHP_OPCACHE" != "no"; then if test "$PHP_OPCACHE_JIT" = "yes"; then case $host_cpu in - i[[34567]]86*|x86*|aarch64) + i[[34567]]86*|x86*|aarch64|amd64) ;; *) AC_MSG_WARN([JIT not supported by host architecture]) @@ -48,7 +48,8 @@ if test "$PHP_OPCACHE" != "no"; then DASM_FLAGS="-D X64APPLE=1 -D X64=1" DASM_ARCH="x86" ;; - x86_64*) + *x86_64*|amd64-*-freebsd*) + IR_TARGET=IR_TARGET_X64 DASM_FLAGS="-D X64=1" DASM_ARCH="x86" ;; diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc index d40aaf904727e..d4e67b6c5a4a6 100644 --- a/ext/opcache/jit/zend_jit_arm64.dasc +++ b/ext/opcache/jit/zend_jit_arm64.dasc @@ -2023,39 +2023,10 @@ static int zend_jit_undefined_offset_ex_stub(dasm_State **Dst) static int zend_jit_undefined_offset_stub(dasm_State **Dst) { |->undefined_offset: -#ifdef __APPLE__ - | stp x29, x30, [sp, # -16]! - | mov x29, sp -#endif - | //sub r4, 8 - | ldr REG0, EX->opline - | ldr REG1w, OP:REG0->result.var - | add REG1, REG1, FP - | SET_Z_TYPE_INFO REG1, IS_NULL, TMP1w - | ldrb REG1w, OP:REG0->op2_type - | cmp REG1w, #IS_CONST - | bne >2 - | ldrsw REG1, OP:REG0->op2.constant - | add REG0, REG0, REG1 - | b >3 - |2: - | ldr REG0w, OP:REG0->op2.var - | add REG0, REG0, FP - |3: - | mov CARG1, #E_WARNING - | LOAD_ADDR CARG2, "Undefined array key " ZEND_LONG_FMT - | ldr CARG3, [REG0] -#ifdef __APPLE__ - | str CARG3, [sp, #-16]! - | EXT_CALL zend_error, REG0 - | add sp, sp, #16 - | ldp x29, x30, [sp], #16 - | ret -#else - | EXT_JMP zend_error, REG0 // tail call - | //add r4, 8 // stack alignment - | //ret -#endif + || if (!GCC_GLOBAL_REGS) { + | mov FCARG1x, FP + || } + | EXT_JMP zend_jit_undefined_long_key, REG0 return 1; } @@ -2072,40 +2043,10 @@ static int zend_jit_undefined_index_ex_stub(dasm_State **Dst) static int zend_jit_undefined_index_stub(dasm_State **Dst) { |->undefined_index: -#ifdef __APPLE__ - | stp x29, x30, [sp, # -16]! - | mov x29, sp -#endif - | //sub r4, 8 - | ldr REG0, EX->opline - | ldr REG1w, OP:REG0->result.var - | add REG1, REG1, FP - | SET_Z_TYPE_INFO REG1, IS_NULL, TMP1w - | ldrb REG1w, OP:REG0->op2_type - | cmp REG1w, #IS_CONST - | bne >2 - | ldrsw REG1, OP:REG0->op2.constant - | add REG0, REG0, REG1 - | b >3 - |2: - | ldr REG0w, OP:REG0->op2.var - | add REG0, REG0, FP - |3: - | mov CARG1, #E_WARNING - | LOAD_ADDR CARG2, "Undefined array key \"%s\"" - | ldr CARG3, [REG0] - | add CARG3, CARG3, #offsetof(zend_string, val) -#ifdef __APPLE__ - | str CARG3, [sp, #-16]! - | EXT_CALL zend_error, REG0 - | add sp, sp, #16 - | ldp x29, x30, [sp], #16 - | ret -#else - | EXT_JMP zend_error, REG0 // tail call - | //add r4, 8 - | //ret -#endif + || if (!GCC_GLOBAL_REGS) { + | mov FCARG1x, FP + || } + | EXT_JMP zend_jit_undefined_string_key, REG0 return 1; } diff --git a/ext/opcache/jit/zend_jit_disasm.c b/ext/opcache/jit/zend_jit_disasm.c index f470cb9a96855..c49a0df863aed 100644 --- a/ext/opcache/jit/zend_jit_disasm.c +++ b/ext/opcache/jit/zend_jit_disasm.c @@ -655,6 +655,8 @@ static int zend_jit_disasm_init(void) REGISTER_HELPER(zend_jit_vm_stack_free_args_helper); REGISTER_HELPER(zend_jit_copy_extra_args_helper); REGISTER_HELPER(zend_jit_deprecated_helper); + REGISTER_HELPER(zend_jit_undefined_long_key); + REGISTER_HELPER(zend_jit_undefined_string_key); REGISTER_HELPER(zend_jit_assign_const_to_typed_ref); REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref); REGISTER_HELPER(zend_jit_assign_var_to_typed_ref); diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 5a68e15588e36..69c7ca3a537c4 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1106,6 +1106,9 @@ static zend_string* ZEND_FASTCALL zend_jit_fetch_dim_str_r_helper(zend_string *s } else { offset = Z_LVAL_P(dim); } + if (UNEXPECTED(EG(exception) != NULL)) { + return ZSTR_EMPTY_ALLOC(); + } return zend_jit_fetch_dim_str_offset(str, offset); } @@ -1135,7 +1138,8 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_str_is_helper(zend_string *str, zva goto try_string_offset; default: zend_jit_illegal_string_offset(dim); - break; + ZVAL_NULL(result); + return; } offset = zval_get_long_func(dim, /* is_strict */ false); @@ -1587,7 +1591,9 @@ static void ZEND_FASTCALL zend_jit_assign_dim_op_helper(zval *container, zval *d } zval_ptr_dtor(&res); } else { - zend_error(E_WARNING, "Attempt to assign property of non-object"); + /* Exception is thrown in this case */ + GC_DELREF(obj); + return; } if (UNEXPECTED(GC_DELREF(obj) == 0)) { zend_objects_store_del(obj); diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index 544bcdd1f245b..92f6fb7b11dc5 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -328,6 +328,8 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_H void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D); bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D); +void ZEND_FASTCALL zend_jit_undefined_long_key(EXECUTE_DATA_D); +void ZEND_FASTCALL zend_jit_undefined_string_key(EXECUTE_DATA_D); zend_constant* ZEND_FASTCALL zend_jit_get_constant(const zval *key, uint32_t flags); zend_constant* ZEND_FASTCALL zend_jit_check_constant(const zval *key); diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 12b59edcfb346..f6da28375b74d 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -5033,6 +5033,21 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info))) { goto jit_failure; } + if (ssa_op->op2_def > 0 + && Z_MODE(op2_addr) == IS_REG + && ssa->vars[ssa_op->op2_def].no_val) { + uint8_t type = (op2_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE; + uint32_t var_num = EX_VAR_TO_NUM(opline->op2.var); + + if (STACK_MEM_TYPE(stack, var_num) != type + && ssa->vars[ssa_op->op2_def].use_chain < 0 + && !ssa->vars[ssa_op->op2_def].phi_use_chain) { + if (!zend_jit_store_var_type(&dasm_state, var_num, type)) { + return 0; + } + SET_STACK_TYPE(stack, var_num, type, 1); + } + } if (opline->op2_type == IS_CV && ssa_op->op2_def >= 0 && ssa->vars[ssa_op->op2_def].alias == NO_ALIAS) { @@ -5069,6 +5084,21 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par res_use_info, res_info, res_addr)) { goto jit_failure; } + if (ssa_op->op1_def > 0 + && Z_MODE(op1_addr) == IS_REG + && ssa->vars[ssa_op->op1_def].no_val) { + uint8_t type = (op1_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE; + uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var); + + if (STACK_MEM_TYPE(stack, var_num) != type + && ssa->vars[ssa_op->op1_def].use_chain < 0 + && !ssa->vars[ssa_op->op1_def].phi_use_chain) { + if (!zend_jit_store_var_type(&dasm_state, var_num, type)) { + return 0; + } + SET_STACK_TYPE(stack, var_num, type, 1); + } + } if (opline->op1_type == IS_CV && ssa_op->op1_def >= 0 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) { @@ -5151,6 +5181,21 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par op1_info, op1_addr, op1_def_addr)) { goto jit_failure; } + if (ssa_op->op1_def > 0 + && Z_MODE(op1_addr) == IS_REG + && ssa->vars[ssa_op->op1_def].no_val) { + uint8_t type = (op1_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE; + uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var); + + if (STACK_MEM_TYPE(stack, var_num) != type + && ssa->vars[ssa_op->op1_def].use_chain < 0 + && !ssa->vars[ssa_op->op1_def].phi_use_chain) { + if (!zend_jit_store_var_type(&dasm_state, var_num, type)) { + return 0; + } + SET_STACK_TYPE(stack, var_num, type, 1); + } + } if (opline->op1_type == IS_CV && ssa_op->op1_def >= 0 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) { @@ -6861,9 +6906,30 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par } } else if (p->stop == ZEND_JIT_TRACE_STOP_LINK || p->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) { - if (!zend_jit_trace_deoptimization(&dasm_state, 0, NULL, - stack, op_array->last_var + op_array->T, NULL, NULL, NULL, 0)) { - goto jit_failure; + if (ra + && (p-1)->op != ZEND_JIT_TRACE_ENTER + && (p-1)->op != ZEND_JIT_TRACE_BACK + && opline->opcode != ZEND_DO_UCALL + && opline->opcode != ZEND_DO_FCALL + && opline->opcode != ZEND_DO_FCALL_BY_NAME + && opline->opcode != ZEND_INCLUDE_OR_EVAL) { + if (!zend_jit_trace_deoptimization(&dasm_state, 0, NULL, + stack, op_array->last_var + op_array->T, NULL, NULL, NULL, 0)) { + goto jit_failure; + } + for (i = 0; i < op_array->last_var; i++) { + int8_t reg = STACK_REG(stack, i); + uint8_t type = STACK_TYPE(stack, i); + + if (reg == ZREG_NONE + && type != IS_UNKNOWN + && type != STACK_MEM_TYPE(stack, i)) { + if (!zend_jit_store_var_type(&dasm_state, i, type)) { + return 0; + } + SET_STACK_TYPE(stack, i, type, 1); + } + } } if (p->stop == ZEND_JIT_TRACE_STOP_LINK) { const void *timeout_exit_addr = NULL; diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index 5342731fc81b7..ff7fbd87546eb 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -199,6 +199,43 @@ bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D) return 1; } +void ZEND_FASTCALL zend_jit_undefined_long_key(EXECUTE_DATA_D) +{ + const zend_op *opline = EX(opline); + zval *result = EX_VAR(opline->result.var); + zval *dim; + + ZVAL_NULL(result); + if (opline->op2_type == IS_CONST) { + dim = RT_CONSTANT(opline, opline->op2); + } else { + dim = EX_VAR(opline->op2.var); + } + ZEND_ASSERT(Z_TYPE_P(dim) == IS_LONG); + zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, Z_LVAL_P(dim)); +} + +void ZEND_FASTCALL zend_jit_undefined_string_key(EXECUTE_DATA_D) +{ + const zend_op *opline = EX(opline); + zval *result = EX_VAR(opline->result.var); + zval *dim; + zend_ulong lval; + + ZVAL_NULL(result); + if (opline->op2_type == IS_CONST) { + dim = RT_CONSTANT(opline, opline->op2); + } else { + dim = EX_VAR(opline->op2.var); + } + ZEND_ASSERT(Z_TYPE_P(dim) == IS_STRING); + if (ZEND_HANDLE_NUMERIC(Z_STR_P(dim), lval)) { + zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, lval); + } else { + zend_error(E_WARNING, "Undefined array key \"%s\"", Z_STRVAL_P(dim)); + } +} + ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_profile_helper(ZEND_OPCODE_HANDLER_ARGS) { zend_op_array *op_array = (zend_op_array*)EX(func); diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index b441b3dc966f1..d881b466dd962 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -1966,50 +1966,10 @@ static int zend_jit_undefined_offset_ex_stub(dasm_State **Dst) static int zend_jit_undefined_offset_stub(dasm_State **Dst) { |->undefined_offset: - |.if X64WIN - | sub r4, 0x28 - |.elif X64 - | sub r4, 8 - |.else - | sub r4, 12 - |.endif - | mov r0, EX->opline - | mov ecx, dword OP:r0->result.var - | cmp byte OP:r0->op2_type, IS_CONST - | SET_Z_TYPE_INFO FP + r1, IS_NULL - | jne >2 - |.if X64 - | movsxd r1, dword OP:r0->op2.constant - | add r0, r1 - |.else - | mov r0, aword OP:r0->op2.zv - |.endif - | jmp >3 - |2: - | mov eax, dword OP:r0->op2.var - | add r0, FP - |3: - |.if X64WIN - | mov CARG1, E_WARNING - | LOAD_ADDR CARG2, "Undefined array key " ZEND_LONG_FMT - | mov CARG3, aword [r0] - | EXT_CALL zend_error, r0 - | add r4, 0x28 // stack alignment - |.elif X64 - | mov CARG1, E_WARNING - | LOAD_ADDR CARG2, "Undefined array key " ZEND_LONG_FMT - | mov CARG3, aword [r0] - | EXT_CALL zend_error, r0 - | add r4, 8 // stack alignment - |.else - | sub r4, 4 - | push aword [r0] - | push "Undefined array key " ZEND_LONG_FMT - | push E_WARNING - | EXT_CALL zend_error, r0 - | add r4, 28 - |.endif - | ret + || if (!GCC_GLOBAL_REGS) { + | mov FCARG1a, FP + || } + | EXT_JMP zend_jit_undefined_long_key, r0 return 1; } @@ -2026,54 +1986,10 @@ static int zend_jit_undefined_index_ex_stub(dasm_State **Dst) static int zend_jit_undefined_index_stub(dasm_State **Dst) { |->undefined_index: - |.if X64WIN - | sub r4, 0x28 - |.elif X64 - | sub r4, 8 - |.else - | sub r4, 12 - |.endif - | mov r0, EX->opline - | mov ecx, dword OP:r0->result.var - | cmp byte OP:r0->op2_type, IS_CONST - | SET_Z_TYPE_INFO FP + r1, IS_NULL - | jne >2 - |.if X64 - | movsxd r1, dword OP:r0->op2.constant - | add r0, r1 - |.else - | mov r0, aword OP:r0->op2.zv - |.endif - | jmp >3 - |2: - | mov eax, dword OP:r0->op2.var - | add r0, FP - |3: - |.if X64WIN - | mov CARG1, E_WARNING - | LOAD_ADDR CARG2, "Undefined array key \"%s\"" - | mov CARG3, aword [r0] - | add CARG3, offsetof(zend_string, val) - | EXT_CALL zend_error, r0 - | add r4, 0x28 - |.elif X64 - | mov CARG1, E_WARNING - | LOAD_ADDR CARG2, "Undefined array key \"%s\"" - | mov CARG3, aword [r0] - | add CARG3, offsetof(zend_string, val) - | EXT_CALL zend_error, r0 - | add r4, 8 - |.else - | sub r4, 4 - | mov r0, aword [r0] - | add r0, offsetof(zend_string, val) - | push r0 - | push "Undefined array key \"%s\"" - | push E_WARNING - | EXT_CALL zend_error, r0 - | add r4, 28 - |.endif - | ret + || if (!GCC_GLOBAL_REGS) { + | mov FCARG1a, FP + || } + | EXT_JMP zend_jit_undefined_string_key, r0 return 1; } diff --git a/ext/opcache/tests/jit/gh12512.phpt b/ext/opcache/tests/jit/gh12512.phpt new file mode 100644 index 0000000000000..35307d18cc61f --- /dev/null +++ b/ext/opcache/tests/jit/gh12512.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-12512: missing type store +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- + $val) { + if ($val === 2) { + unset($a[$key]); + } + } + return $ret; +} + +function foo($a, bool $b): bool { + if ($b) return true; + $n2 = count($a); + do { + $n = $n2; + $res = bar($a); + $n2 = count($a); + } while ($res === null && $n !== $n2); + + if ($res === null && $n === 0) { + return false; + } + return true; +} + +$a = [1,'a'=>5]; +bar($a); +foo([1,'a'=>5], true); +foo([1,'a'=>5], false); +foo([2,'a'=>5], false); +?> +DONE +--EXPECT-- +DONE diff --git a/ext/opcache/tests/jit/gh12512_2.phpt b/ext/opcache/tests/jit/gh12512_2.phpt new file mode 100644 index 0000000000000..67c5b091494c3 --- /dev/null +++ b/ext/opcache/tests/jit/gh12512_2.phpt @@ -0,0 +1,44 @@ +--TEST-- +GH-12512: missing type store +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- + $y; + } + if ($exit) { + return $n; + } + } + + return $n; +} +var_dump(foo([1,2,3,4,5,6,7,8], 1)); +var_dump(foo([1,2,3,4,5,6,7,8], 1)); +var_dump(foo([1,2,3,4,5,6,7,8], 0)); +?> +DONE +--EXPECT-- +int(0) +int(0) +int(0) +DONE diff --git a/ext/opcache/tests/jit/gh12723-A.phpt b/ext/opcache/tests/jit/gh12723-A.phpt new file mode 100644 index 0000000000000..f30453e8c0a37 --- /dev/null +++ b/ext/opcache/tests/jit/gh12723-A.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-12723: Function JIT emits "Uninitialized string offset" warning at the same time as invalid offset Error +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +Cannot access offset of type array on string diff --git a/ext/opcache/tests/jit/gh12723-B.phpt b/ext/opcache/tests/jit/gh12723-B.phpt new file mode 100644 index 0000000000000..9f5ae7a19ff16 --- /dev/null +++ b/ext/opcache/tests/jit/gh12723-B.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-12723: JIT emits "Attempt to assign property of non-object" warning at the same time as Error is being thrown +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +Cannot use object of type stdClass as array diff --git a/ext/opcache/tests/jit/gh12748.phpt b/ext/opcache/tests/jit/gh12748.phpt new file mode 100644 index 0000000000000..d7580fdb9ab7c --- /dev/null +++ b/ext/opcache/tests/jit/gh12748.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-12748: Function JIT emits "could not convert to int" warning at the same time as invalid offset Error +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- +getMessage(), "\n"; +} +try { + echo "empty():\n"; + var_dump(empty($container[new stdClass()])); +} catch (\Throwable $e) { + echo $e->getMessage(), "\n"; +} +try { + echo "Coalesce():\n"; + var_dump($container[new stdClass()] ?? 'default'); +} catch (\Throwable $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +isset(): +bool(false) +empty(): +bool(true) +Coalesce(): +Cannot access offset of type stdClass on string diff --git a/ext/opcache/tests/jit/gh12812.phpt b/ext/opcache/tests/jit/gh12812.phpt new file mode 100644 index 0000000000000..267abf2aae064 --- /dev/null +++ b/ext/opcache/tests/jit/gh12812.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-12812: JIT: Integer string in variable used as offset produces wrong undefined array key warning +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- +getMessage(), "\n"; +} +try { + var_dump($container[$dimension]); +} catch (\Throwable $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +Warning: Undefined array key 7 in %s on line %d +NULL + +Warning: Undefined array key 7 in %s on line %d +NULL diff --git a/ext/opcache/tests/opt/inference_023.phpt b/ext/opcache/tests/opt/inference_023.phpt new file mode 100644 index 0000000000000..0949972796eb9 --- /dev/null +++ b/ext/opcache/tests/opt/inference_023.phpt @@ -0,0 +1,24 @@ +--TEST-- +Type inference 023: FETCH_DIM_W +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- += 0) { + $a[$n]->x = 2; + } + $n++; + $a[$n] = new stdClass(); + $a[$n]->x = 1; + } +} +?> +DONE +--EXPECT-- +DONE diff --git a/ext/opcache/tests/opt/inference_024.phpt b/ext/opcache/tests/opt/inference_024.phpt new file mode 100644 index 0000000000000..a34ac5c1ece51 --- /dev/null +++ b/ext/opcache/tests/opt/inference_024.phpt @@ -0,0 +1,23 @@ +--TEST-- +Type inference 024: FETCH_DIM_W +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- + +DONE +--EXPECT-- +DONE diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 4fc22ef594f01..0f8adf013515c 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -5266,7 +5266,7 @@ PHP_FUNCTION(openssl_pkcs7_verify) signersfilename, signersfilename_len, 3, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY)); if (certout) { int i; - signers = PKCS7_get0_signers(p7, NULL, (int)flags); + signers = PKCS7_get0_signers(p7, others, (int)flags); if (signers != NULL) { for (i = 0; i < sk_X509_num(signers); i++) { diff --git a/ext/openssl/tests/CertificateGenerator.inc b/ext/openssl/tests/CertificateGenerator.inc index c36718cd54844..12764c8b63d2c 100644 --- a/ext/openssl/tests/CertificateGenerator.inc +++ b/ext/openssl/tests/CertificateGenerator.inc @@ -85,8 +85,8 @@ class CertificateGenerator openssl_x509_export_to_file($this->ca, $file); } - public function saveNewCertAndKey( - $commonNameForCert, $certFile, $keyFile, $keyLength = null, $subjectAltName = null + private function generateCertAndKey( + $commonNameForCert, $file, $keyLength = null, $subjectAltName = null ) { $dn = [ 'countryName' => 'BY', @@ -117,51 +117,53 @@ $subjectAltNameConfig basicConstraints = CA:FALSE $subjectAltNameConfig CONFIG; - $configFile = $certFile . '.cnf'; + $configFile = $file . '.cnf'; file_put_contents($configFile, $configCode); - try { - $config = [ - 'config' => $configFile, - 'req_extensions' => 'v3_req', - 'x509_extensions' => 'usr_cert', - ]; - - $this->lastKey = self::generateKey($keyLength); - $csr = openssl_csr_new($dn, $this->lastKey, $config); - $this->lastCert = openssl_csr_sign( - $csr, - $this->ca, - $this->caKey, - /* days */ 2, - $config, - ); - if (!$this->lastCert) { - throw new Exception('Failed to create certificate'); - } - - $certText = ''; - openssl_x509_export($this->lastCert, $certText); - - $keyText = ''; - openssl_pkey_export($this->lastKey, $keyText, null, $config); - - if ($certFile === $keyFile) { - file_put_contents($certFile, $certText . PHP_EOL . $keyText); - } else { - file_put_contents($certFile, $certText); - file_put_contents($keyFile, $keyText); - } - } finally { - unlink($configFile); - } - } + $config = [ + 'config' => $configFile, + 'req_extensions' => 'v3_req', + 'x509_extensions' => 'usr_cert', + ]; + + $this->lastKey = self::generateKey($keyLength); + $csr = openssl_csr_new($dn, $this->lastKey, $config); + $this->lastCert = openssl_csr_sign( + $csr, + $this->ca, + $this->caKey, + /* days */ 2, + $config, + ); + return $config; + } public function saveNewCertAsFileWithKey( $commonNameForCert, $file, $keyLength = null, $subjectAltName = null ) { - $this->saveNewCertAndKey($commonNameForCert, $file, $file, $keyLength, $subjectAltName); + $config = $this->generateCertAndKey($commonNameForCert, $file, $keyLength, $subjectAltName); + + $certText = ''; + openssl_x509_export($this->lastCert, $certText); + + $keyText = ''; + openssl_pkey_export($this->lastKey, $keyText, null, $config); + + file_put_contents($file, $certText . PHP_EOL . $keyText); + + unlink($config['config']); + } + + public function saveNewCertAndKey( + $commonNameForCert, $certFile, $keyFile, $keyLength = null, $subjectAltName = null + ) { + $config = $this->generateCertAndKey($commonNameForCert, $certFile, $keyLength, $subjectAltName); + + openssl_x509_export_to_file($this->lastCert, $certFile); + openssl_pkey_export_to_file($this->lastKey, $keyFile, null, $config); + + unlink($config['config']); } public function getCertDigest($algo) diff --git a/ext/openssl/tests/bug50713.phpt b/ext/openssl/tests/bug50713.phpt new file mode 100644 index 0000000000000..95eff2e75f90a --- /dev/null +++ b/ext/openssl/tests/bug50713.phpt @@ -0,0 +1,40 @@ +--TEST-- +Bug #50713 (openssl_pkcs7_verify() may ignore untrusted CAs) +--EXTENSIONS-- +openssl +--FILE-- +saveCaCert($cacertFile); +$certificateGenerator->saveNewCertAndKey('bug50713', $certFile, $keyFile, 1024); + +var_dump(openssl_pkcs7_sign($inFile, $outFile, 'file://' . $certFile, 'file://' . $keyFile, [], PKCS7_NOCERTS)); +var_dump(openssl_pkcs7_verify($outFile, 0, $signersFile, [$cacertFile], $certFile)); +var_dump(strlen(file_get_contents($signersFile)) > 0); +?> +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) diff --git a/ext/pcre/tests/gh11374.phpt b/ext/pcre/tests/gh11374.phpt index 07f8f4bccfd0a..29f6485cc0440 100644 --- a/ext/pcre/tests/gh11374.phpt +++ b/ext/pcre/tests/gh11374.phpt @@ -1,5 +1,11 @@ --TEST-- GH-11374 (PCRE regular expression without JIT enabled gives different result) +--EXTENSIONS-- +zend_test +--SKIPIF-- + --FILE-- +--FILE-- + +--EXPECT-- +OK diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c index 5c833dc45cf04..b731114775ad7 100644 --- a/ext/soap/php_sdl.c +++ b/ext/soap/php_sdl.c @@ -332,7 +332,7 @@ static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include) sdl_restore_uri_credentials(ctx); if (!wsdl) { - xmlErrorPtr xmlErrorPtr = xmlGetLastError(); + const xmlError *xmlErrorPtr = xmlGetLastError(); if (xmlErrorPtr) { soap_error2(E_ERROR, "Parsing WSDL: Couldn't load from '%s' : %s", struri, xmlErrorPtr->message); @@ -2381,7 +2381,9 @@ static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr s /* Make sure that incomplete files (e.g. due to disk space issues, see bug #66150) are not utilised. */ if (valid_file) { /* This is allowed to fail, this means that another process was raced to create the file. */ - (void) VCWD_RENAME(ZSTR_VAL(temp_file_path), fn); + if (VCWD_RENAME(ZSTR_VAL(temp_file_path), fn) < 0) { + VCWD_UNLINK(ZSTR_VAL(temp_file_path)); + } } smart_str_free(&buf); diff --git a/ext/soap/tests/bug75306.phpt b/ext/soap/tests/bug75306.phpt index 7501fde59e6b8..2998ddddff431 100644 --- a/ext/soap/tests/bug75306.phpt +++ b/ext/soap/tests/bug75306.phpt @@ -7,11 +7,11 @@ soap $options = array("cache_wsdl" => WSDL_CACHE_NONE); // Need a warm-up for globals for ($i = 0; $i < 10; $i++) { - $client = new SoapClient("ext/soap/tests/test.wsdl", $options); + $client = new SoapClient(__DIR__ . "/test.wsdl", $options); } $usage = memory_get_usage(); for ($i = 0; $i < 10; $i++) { - $client = new SoapClient("ext/soap/tests/test.wsdl", $options); + $client = new SoapClient(__DIR__ . "/test.wsdl", $options); } $usage_delta = memory_get_usage() - $usage; var_dump($usage_delta); diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 710b2f97ffb9a..715b10c456dea 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -585,8 +585,10 @@ PHP_FUNCTION(spl_autoload_unregister) if (fcc.function_handler && zend_string_equals_literal( fcc.function_handler->common.function_name, "spl_autoload_call")) { - /* Don't destroy the hash table, as we might be iterating over it right now. */ - zend_hash_clean(spl_autoload_functions); + if (spl_autoload_functions) { + /* Don't destroy the hash table, as we might be iterating over it right now. */ + zend_hash_clean(spl_autoload_functions); + } RETURN_TRUE; } diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 0dcb34b6a6975..581183d38f49e 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -925,7 +925,6 @@ PHP_METHOD(SplFileInfo, getFilename) path = spl_filesystem_object_get_path(intern); - ZEND_ASSERT(path); if (path && ZSTR_LEN(path) && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) { /* +1 to skip the trailing / of the path in the file name */ size_t path_len = ZSTR_LEN(path) + 1; @@ -933,7 +932,9 @@ PHP_METHOD(SplFileInfo, getFilename) } else { RETVAL_STR_COPY(intern->file_name); } - zend_string_release_ex(path, /* persistent */ false); + if (path) { + zend_string_release_ex(path, /* persistent */ false); + } } /* }}} */ @@ -973,14 +974,16 @@ PHP_METHOD(SplFileInfo, getExtension) path = spl_filesystem_object_get_path(intern); - if (ZSTR_LEN(path) && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) { + if (path && ZSTR_LEN(path) && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) { fname = ZSTR_VAL(intern->file_name) + ZSTR_LEN(path) + 1; flen = ZSTR_LEN(intern->file_name) - (ZSTR_LEN(path) + 1); } else { fname = ZSTR_VAL(intern->file_name); flen = ZSTR_LEN(intern->file_name); } - zend_string_release_ex(path, /* persistent */ false); + if (path) { + zend_string_release_ex(path, /* persistent */ false); + } ret = php_basename(fname, flen, NULL, 0); @@ -1052,7 +1055,9 @@ PHP_METHOD(SplFileInfo, getBasename) fname = ZSTR_VAL(intern->file_name); flen = ZSTR_LEN(intern->file_name); } - zend_string_release_ex(path, /* persistent */ false); + if (path) { + zend_string_release_ex(path, /* persistent */ false); + } RETURN_STR(php_basename(fname, flen, suffix, slen)); } diff --git a/ext/spl/tests/gh12721.phpt b/ext/spl/tests/gh12721.phpt new file mode 100644 index 0000000000000..4310afcdd933f --- /dev/null +++ b/ext/spl/tests/gh12721.phpt @@ -0,0 +1,51 @@ +--TEST-- +GH-12721 (SplFileInfo::getFilename() segfault in combination with GlobIterator and no directory separator) +--FILE-- +getFilename(), "\n"; + echo $fileInfo->getExtension(), "\n"; + echo $fileInfo->getBasename(), "\n"; + var_dump($fileInfo->getFileInfo()); +} + +echo "--- With slash ---\n"; + +foreach (new GlobIterator('./*.gh12721') as $fileInfo) { + echo $fileInfo->getFilename(), "\n"; + echo $fileInfo->getExtension(), "\n"; + echo $fileInfo->getBasename(), "\n"; + var_dump($fileInfo->getFileInfo()); +} + +?> +--CLEAN-- + +--EXPECTF-- +--- No slash --- +file1.gh12721 +gh12721 +file1.gh12721 +object(SplFileInfo)#4 (2) { + ["pathName":"SplFileInfo":private]=> + string(13) "file1.gh12721" + ["fileName":"SplFileInfo":private]=> + string(13) "file1.gh12721" +} +--- With slash --- +file1.gh12721 +gh12721 +file1.gh12721 +object(SplFileInfo)#3 (2) { + ["pathName":"SplFileInfo":private]=> + string(15) "%sfile1.gh12721" + ["fileName":"SplFileInfo":private]=> + string(13) "file1.gh12721" +} diff --git a/ext/spl/tests/spl_autoload_unregister_without_registrations.phpt b/ext/spl/tests/spl_autoload_unregister_without_registrations.phpt new file mode 100644 index 0000000000000..0a7ca5a1352fd --- /dev/null +++ b/ext/spl/tests/spl_autoload_unregister_without_registrations.phpt @@ -0,0 +1,10 @@ +--TEST-- +spl_autoload_unregister("spl_autoload_call") without registrations +--FILE-- + +Done +--EXPECT-- +bool(true) +Done diff --git a/ext/sqlite3/tests/sqlite3_defensive.phpt b/ext/sqlite3/tests/sqlite3_defensive.phpt index 033e661d8a393..056f716170c4c 100644 --- a/ext/sqlite3/tests/sqlite3_defensive.phpt +++ b/ext/sqlite3/tests/sqlite3_defensive.phpt @@ -20,7 +20,6 @@ var_dump($db->exec('CREATE TABLE test (a, b);')); // This does not generate an error! var_dump($db->exec('PRAGMA writable_schema = ON;')); -var_dump($db->querySingle('PRAGMA writable_schema;')); // Should be 1 var_dump($db->querySingle('SELECT COUNT(*) FROM sqlite_master;')); @@ -35,8 +34,7 @@ var_dump($db->querySingle('SELECT COUNT(*) FROM sqlite_master;')); bool(true) bool(true) int(1) -int(1) Warning: SQLite3::querySingle(): Unable to prepare statement: 1, table sqlite_master may not be modified in %s on line %d bool(false) -int(1) \ No newline at end of file +int(1) diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 6967307df453e..3517b514420d5 100755 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -229,6 +229,8 @@ static void basic_globals_ctor(php_basic_globals *basic_globals_p) /* {{{ */ BG(page_uid) = -1; BG(page_gid) = -1; + + BG(syslog_device) = NULL; } /* }}} */ @@ -366,9 +368,6 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */ PHP_MSHUTDOWN_FUNCTION(basic) /* {{{ */ { -#ifdef HAVE_SYSLOG_H - PHP_MSHUTDOWN(syslog)(SHUTDOWN_FUNC_ARGS_PASSTHRU); -#endif #ifdef ZTS ts_free_id(basic_globals_id); #ifdef PHP_WIN32 @@ -425,9 +424,6 @@ PHP_RINIT_FUNCTION(basic) /* {{{ */ BG(user_shutdown_function_names) = NULL; PHP_RINIT(filestat)(INIT_FUNC_ARGS_PASSTHRU); -#ifdef HAVE_SYSLOG_H - BASIC_RINIT_SUBMODULE(syslog) -#endif BASIC_RINIT_SUBMODULE(dir) BASIC_RINIT_SUBMODULE(url_scanner_ex) @@ -477,9 +473,7 @@ PHP_RSHUTDOWN_FUNCTION(basic) /* {{{ */ PHP_RSHUTDOWN(filestat)(SHUTDOWN_FUNC_ARGS_PASSTHRU); #ifdef HAVE_SYSLOG_H -#ifdef PHP_WIN32 - BASIC_RSHUTDOWN_SUBMODULE(syslog)(SHUTDOWN_FUNC_ARGS_PASSTHRU); -#endif + BASIC_RSHUTDOWN_SUBMODULE(syslog); #endif BASIC_RSHUTDOWN_SUBMODULE(assert) BASIC_RSHUTDOWN_SUBMODULE(url_scanner_ex) @@ -1547,7 +1541,7 @@ PHP_FUNCTION(forward_static_call) Z_PARAM_VARIADIC('*', fci.params, fci.param_count) ZEND_PARSE_PARAMETERS_END(); - if (!EX(prev_execute_data)->func->common.scope) { + if (!EX(prev_execute_data) || !EX(prev_execute_data)->func->common.scope) { zend_throw_error(NULL, "Cannot call forward_static_call() when no class scope is active"); RETURN_THROWS(); } diff --git a/ext/standard/browscap.c b/ext/standard/browscap.c index 4fa766e3df802..d7b53e659939d 100644 --- a/ext/standard/browscap.c +++ b/ext/standard/browscap.c @@ -228,7 +228,7 @@ static zend_string *browscap_intern_str( } else { interned = zend_string_copy(str); if (persistent) { - interned = zend_new_interned_string(str); + interned = zend_new_interned_string(interned); } zend_hash_add_new_ptr(&ctx->str_interned, interned, interned); } @@ -397,10 +397,6 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb } /* }}} */ -static void str_interned_dtor(zval *zv) { - zend_string_release(Z_STR_P(zv)); -} - static int browscap_read_file(char *filename, browser_data *browdata, int persistent) /* {{{ */ { zend_file_handle fh; @@ -430,7 +426,9 @@ static int browscap_read_file(char *filename, browser_data *browdata, int persis ctx.bdata = browdata; ctx.current_entry = NULL; ctx.current_section_name = NULL; - zend_hash_init(&ctx.str_interned, 8, NULL, str_interned_dtor, persistent); + /* No dtor because we don't inc the refcount for the reference stored within the hash table's entry value + * as the hash table is only temporary anyway. */ + zend_hash_init(&ctx.str_interned, 8, NULL, NULL, persistent); zend_parse_ini_file(&fh, persistent, ZEND_INI_SCANNER_RAW, (zend_ini_parser_cb_t) php_browscap_parser_cb, &ctx); diff --git a/ext/standard/php_ext_syslog.h b/ext/standard/php_ext_syslog.h index 5e091fb5280df..fd7958fad2929 100644 --- a/ext/standard/php_ext_syslog.h +++ b/ext/standard/php_ext_syslog.h @@ -22,11 +22,7 @@ #include "php_syslog.h" PHP_MINIT_FUNCTION(syslog); -PHP_RINIT_FUNCTION(syslog); -#ifdef PHP_WIN32 PHP_RSHUTDOWN_FUNCTION(syslog); -#endif -PHP_MSHUTDOWN_FUNCTION(syslog); #endif diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 53ec6faa1019e..866c7a3c896e2 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -1096,6 +1096,7 @@ PHP_FUNCTION(proc_open) descriptors[ndesc].index = (int)nindex; + ZVAL_DEREF(descitem); if (Z_TYPE_P(descitem) == IS_RESOURCE) { if (set_proc_descriptor_from_resource(descitem, &descriptors[ndesc], ndesc) == FAILURE) { goto exit_fail; diff --git a/ext/standard/syslog.c b/ext/standard/syslog.c index f806e74a03b63..c5d73eb008ec5 100644 --- a/ext/standard/syslog.c +++ b/ext/standard/syslog.c @@ -35,29 +35,13 @@ /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(syslog) { - BG(syslog_device)=NULL; - return SUCCESS; } /* }}} */ -PHP_RINIT_FUNCTION(syslog) -{ - BG(syslog_device) = NULL; - return SUCCESS; -} - - -#ifdef PHP_WIN32 PHP_RSHUTDOWN_FUNCTION(syslog) { - closelog(); - return SUCCESS; -} -#endif - -PHP_MSHUTDOWN_FUNCTION(syslog) -{ + php_closelog(); if (BG(syslog_device)) { free(BG(syslog_device)); BG(syslog_device) = NULL; diff --git a/ext/standard/tests/file/005_variation2.phpt b/ext/standard/tests/file/005_variation2.phpt index 55d1d6666098c..270a6cfbdd84c 100644 --- a/ext/standard/tests/file/005_variation2.phpt +++ b/ext/standard/tests/file/005_variation2.phpt @@ -28,6 +28,11 @@ function stat_fn( $filename ) { echo "*** Testing fileattime(), filemtime(), filectime() & touch() : usage variations ***\n"; echo "\n*** testing touch ***\n"; + +$dir = __DIR__ . '/005_variation2'; +mkdir($dir); +chdir($dir); + $b = touch(false); $c = touch(''); $d = touch(' '); @@ -47,6 +52,7 @@ stat_fn('|'); var_dump(unlink(' ')); var_dump(unlink('|')); +rmdir($dir); echo "Done"; ?> diff --git a/ext/standard/tests/file/file.inc b/ext/standard/tests/file/file.inc index d4ad02a363bd5..c972784f9da36 100644 --- a/ext/standard/tests/file/file.inc +++ b/ext/standard/tests/file/file.inc @@ -590,9 +590,9 @@ $all_stat_keys = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, "rdev", "size", "atime", "mtime", "ctime", "blksize", "blocks"); -$stat_time_diff_keys = array(8, 'atime'); - function compare_stats($stat1, $stat2, $fields, $op = "==", $flag = false ) { + $stat_time_diff_keys = array(8, 'atime'); + // dump the stat if requested if ( $flag == true ) { var_dump($stat1); @@ -608,10 +608,10 @@ function compare_stats($stat1, $stat2, $fields, $op = "==", $flag = false ) { { case "==": if ( $stat1[ $fields[$index] ] != $stat2[ $fields[$index] ] ) { - if ( ! in_array( $index, $stat_time_diff_keys ) ) { + if ( ! in_array( $fields[$index], $stat_time_diff_keys ) ) { $result = false; echo "Error: stat1 do not match with stat2 at key value: $fields[$index]\n"; - } elseif (abs($stat1[ $fields[$index] ] - $stat2[ $fields[$index] ]) > 1) { + } elseif (abs($stat1[ $fields[$index] ] - $stat2[ $fields[$index] ]) > 2) { $result = false; echo "Error: stat1 differs too much from stat2 at key value: $fields[$index]\n"; } diff --git a/ext/standard/tests/file/is_readable_basic.phpt b/ext/standard/tests/file/is_readable_basic.phpt index 7f1b85501a357..38d075439a3f2 100644 --- a/ext/standard/tests/file/is_readable_basic.phpt +++ b/ext/standard/tests/file/is_readable_basic.phpt @@ -15,7 +15,7 @@ require __DIR__.'/file.inc'; echo "*** Testing is_readable(): basic functionality ***\n"; // create a file -$filename = __DIR__."/is_readable.tmp"; +$filename = __DIR__."/is_readable_basic.tmp"; create_file($filename); $counter = 1; diff --git a/ext/standard/tests/file/is_readable_error.phpt b/ext/standard/tests/file/is_readable_error.phpt index 8df7ff92d526c..c013f7fbb7049 100644 --- a/ext/standard/tests/file/is_readable_error.phpt +++ b/ext/standard/tests/file/is_readable_error.phpt @@ -3,7 +3,7 @@ Test is_readable() function: error conditions --FILE-- diff --git a/ext/standard/tests/general_functions/gh12655.phpt b/ext/standard/tests/general_functions/gh12655.phpt new file mode 100644 index 0000000000000..c0235ee6ae6fb --- /dev/null +++ b/ext/standard/tests/general_functions/gh12655.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-12655 (proc_open(): Argument #2 ($descriptor_spec) must only contain arrays and streams [Descriptor item must be either an array or a File-Handle]) +--FILE-- + [ "pipe", "r" ], // stdin is a pipe that the child will read from + 1 => [ "pipe", "w" ], // stdout is a pipe that the child will write to + 2 => [ "pipe", "w" ], // stderr is a file to write to +]; + +foreach ( $descriptor_spec as $fd => &$d ) +{ + // don't do anything, just the fact that we used "&$d" will sink the ship! +} + +$proc = proc_open(PHP_BINARY, $descriptor_spec, $pipes); +echo $proc === false ? "FAILED\n" : "SUCCEEDED\n"; + +?> +--EXPECT-- +SUCCEEDED diff --git a/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_01.phpt b/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_01.phpt new file mode 100644 index 0000000000000..ee102894cb779 --- /dev/null +++ b/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_01.phpt @@ -0,0 +1,15 @@ +--TEST-- +register_shutdown_function() without a previous call frame 01 +--FILE-- + +Done +--EXPECT-- +Done + +Fatal error: Uncaught Error: Cannot call forward_static_call() when no class scope is active in [no active file]:0 +Stack trace: +#0 [internal function]: forward_static_call('hash_hkdf') +#1 {main} + thrown in [no active file] on line 0 diff --git a/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_02.phpt b/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_02.phpt new file mode 100644 index 0000000000000..69826ac562e25 --- /dev/null +++ b/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_02.phpt @@ -0,0 +1,15 @@ +--TEST-- +register_shutdown_function() without a previous call frame 02 +--FILE-- + +Done +--EXPECT-- +Done + +Fatal error: Uncaught Error: Cannot call func_get_args() dynamically in [no active file]:0 +Stack trace: +#0 [internal function]: func_get_args() +#1 {main} + thrown in [no active file] on line 0 diff --git a/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_03.phpt b/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_03.phpt new file mode 100644 index 0000000000000..dd847b2bb0b6a --- /dev/null +++ b/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_03.phpt @@ -0,0 +1,15 @@ +--TEST-- +register_shutdown_function() without a previous call frame 03 +--FILE-- + +Done +--EXPECT-- +Done + +Fatal error: Uncaught Error: Cannot call func_num_args() dynamically in [no active file]:0 +Stack trace: +#0 [internal function]: func_num_args() +#1 {main} + thrown in [no active file] on line 0 diff --git a/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_04.phpt b/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_04.phpt new file mode 100644 index 0000000000000..220af3a67ff97 --- /dev/null +++ b/ext/standard/tests/general_functions/register_shutdown_functions_without_previous_call_frame_04.phpt @@ -0,0 +1,15 @@ +--TEST-- +register_shutdown_function() without a previous call frame 04 +--FILE-- + +Done +--EXPECT-- +Done + +Fatal error: Uncaught ArgumentCountError: func_get_arg() expects exactly 1 argument, 0 given in [no active file]:0 +Stack trace: +#0 [internal function]: func_get_arg() +#1 {main} + thrown in [no active file] on line 0 diff --git a/ext/tidy/tests/parsing_file_too_large.phpt b/ext/tidy/tests/parsing_file_too_large.phpt index 25829bf4e9595..46196c0a5fdce 100644 --- a/ext/tidy/tests/parsing_file_too_large.phpt +++ b/ext/tidy/tests/parsing_file_too_large.phpt @@ -7,6 +7,7 @@ tidy if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); if (getenv("SKIP_SLOW_TESTS")) die("skip slow test"); if (getenv("SKIP_ASAN")) die("skip too big for asan"); +if (getenv("GITHUB_ACTIONS")) die("skip potentially crashes on GitHub actions"); ?> --CONFLICTS-- all diff --git a/ext/xml/tests/bug81351.phpt b/ext/xml/tests/bug81351.phpt index 78aea041046f7..7380a9a937008 100644 --- a/ext/xml/tests/bug81351.phpt +++ b/ext/xml/tests/bug81351.phpt @@ -21,6 +21,6 @@ $code = xml_get_error_code($parser); $error = xml_error_string($code); echo "xml_parse returned $success, xml_get_error_code = $code, xml_error_string = $error\r\n"; ?> ---EXPECT-- +--EXPECTF-- xml_parse returned 1, xml_get_error_code = 0, xml_error_string = No error -xml_parse returned 0, xml_get_error_code = 5, xml_error_string = Invalid document end +%rxml_parse returned 0, xml_get_error_code = 5, xml_error_string = Invalid document end|xml_parse returned 0, xml_get_error_code = 77, xml_error_string = Tag not finished%r diff --git a/ext/xml/tests/xml_error_string_basic.phpt b/ext/xml/tests/xml_error_string_basic.phpt index 86dede1730f7e..a23ec8741d592 100644 --- a/ext/xml/tests/xml_error_string_basic.phpt +++ b/ext/xml/tests/xml_error_string_basic.phpt @@ -21,9 +21,9 @@ foreach ($xmls as $xml) { xml_parser_free($xml_parser); } ?> ---EXPECT-- -int(5) -string(20) "Invalid document end" +--EXPECTF-- +int(%r5|77%r) +string(%d) %r"Invalid document end"|"Tag not finished"%r int(47) string(35) "Processing Instruction not finished" int(57) diff --git a/ext/zend_test/php_test.h b/ext/zend_test/php_test.h index 24895f11df4b3..89570d1155cea 100644 --- a/ext/zend_test/php_test.h +++ b/ext/zend_test/php_test.h @@ -55,6 +55,9 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test) int register_passes; bool print_stderr_mshutdown; zend_long limit_copy_file_range; + int observe_opline_in_zendmm; + zend_mm_heap* zend_orig_heap; + zend_mm_heap* zend_test_heap; zend_test_fiber *active_fiber; zend_long quantity_value; zend_string *str_test; diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 4371459a910bd..901cd8e3063da 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -30,9 +30,16 @@ #include "zend_interfaces.h" #include "zend_weakrefs.h" #include "Zend/Optimizer/zend_optimizer.h" +#include "Zend/zend_alloc.h" #include "test.h" #include "test_arginfo.h" +// `php.h` sets `NDEBUG` when not `PHP_DEBUG` which will make `assert()` from +// assert.h a no-op. In order to have `assert()` working on NDEBUG builds, we +// undefine `NDEBUG` and re-include assert.h +#undef NDEBUG +#include "assert.h" + #if defined(HAVE_LIBXML) && !defined(PHP_WIN32) # include # include @@ -58,6 +65,7 @@ static zend_class_entry *zend_test_ns2_ns_foo_class; static zend_class_entry *zend_test_unit_enum; static zend_class_entry *zend_test_string_enum; static zend_class_entry *zend_test_int_enum; +static zend_class_entry *zend_test_magic_call; static zend_object_handlers zend_test_class_handlers; static ZEND_FUNCTION(zend_test_func) @@ -501,6 +509,78 @@ static ZEND_FUNCTION(zend_test_crash) php_printf("%s", invalid); } +static bool has_opline(zend_execute_data *execute_data) +{ + return execute_data + && execute_data->func + && ZEND_USER_CODE(execute_data->func->type) + && execute_data->opline + ; +} + +void * zend_test_custom_malloc(size_t len) +{ + if (has_opline(EG(current_execute_data))) { + assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1); + } + return _zend_mm_alloc(ZT_G(zend_orig_heap), len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC); +} + +void zend_test_custom_free(void *ptr) +{ + if (has_opline(EG(current_execute_data))) { + assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1); + } + _zend_mm_free(ZT_G(zend_orig_heap), ptr ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC); +} + +void * zend_test_custom_realloc(void * ptr, size_t len) +{ + if (has_opline(EG(current_execute_data))) { + assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1); + } + return _zend_mm_realloc(ZT_G(zend_orig_heap), ptr, len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC); +} + +static PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM) +{ + if (new_value == NULL) { + return FAILURE; + } + + int int_value = zend_ini_parse_bool(new_value); + + if (int_value == 1) { + // `zend_mm_heap` is a private struct, so we have not way to find the + // actual size, but 4096 bytes should be enough + ZT_G(zend_test_heap) = malloc(4096); + memset(ZT_G(zend_test_heap), 0, 4096); + zend_mm_set_custom_handlers( + ZT_G(zend_test_heap), + zend_test_custom_malloc, + zend_test_custom_free, + zend_test_custom_realloc + ); + ZT_G(zend_orig_heap) = zend_mm_get_heap(); + zend_mm_set_heap(ZT_G(zend_test_heap)); + } else if (ZT_G(zend_test_heap)) { + free(ZT_G(zend_test_heap)); + ZT_G(zend_test_heap) = NULL; + zend_mm_set_heap(ZT_G(zend_orig_heap)); + } + return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); +} + +static ZEND_FUNCTION(zend_test_is_pcre_bundled) +{ + ZEND_PARSE_PARAMETERS_NONE(); +#if HAVE_BUNDLED_PCRE + RETURN_TRUE; +#else + RETURN_FALSE; +#endif +} + static zend_object *zend_test_class_new(zend_class_entry *class_type) { zend_object *obj = zend_objects_new(class_type); @@ -723,6 +803,24 @@ static ZEND_METHOD(ZendTestForbidDynamicCall, callStatic) zend_forbid_dynamic_call(); } +static ZEND_METHOD(_ZendTestMagicCall, __call) +{ + zend_string *name; + zval *arguments; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_STR(name) + Z_PARAM_ARRAY(arguments) + ZEND_PARSE_PARAMETERS_END(); + + zval name_zv; + ZVAL_STR(&name_zv, name); + + zend_string_addref(name); + Z_TRY_ADDREF_P(arguments); + RETURN_ARR(zend_new_pair(&name_zv, arguments)); +} + PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_BOOLEAN("zend_test.register_passes", "0", PHP_INI_SYSTEM, OnUpdateBool, register_passes, zend_zend_test_globals, zend_test_globals) @@ -733,6 +831,7 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("zend_test.quantity_value", "0", PHP_INI_ALL, OnUpdateLong, quantity_value, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_ENTRY("zend_test.str_test", "", PHP_INI_ALL, OnUpdateStr, str_test, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_ENTRY("zend_test.not_empty_str_test", "val", PHP_INI_ALL, OnUpdateStrNotEmpty, not_empty_str_test, zend_zend_test_globals, zend_test_globals) + STD_PHP_INI_BOOLEAN("zend_test.observe_opline_in_zendmm", "0", PHP_INI_ALL, OnUpdateZendTestObserveOplineInZendMM, observe_opline_in_zendmm, zend_zend_test_globals, zend_test_globals) PHP_INI_END() void (*old_zend_execute_ex)(zend_execute_data *execute_data); @@ -834,6 +933,8 @@ PHP_MINIT_FUNCTION(zend_test) zend_test_string_enum = register_class_ZendTestStringEnum(); zend_test_int_enum = register_class_ZendTestIntEnum(); + zend_test_magic_call = register_class__ZendTestMagicCall(); + zend_register_functions(NULL, ext_function_legacy, NULL, EG(current_module)->type); // Loading via dl() not supported with the observer API @@ -889,6 +990,13 @@ PHP_RSHUTDOWN_FUNCTION(zend_test) zend_weakrefs_hash_del(&ZT_G(global_weakmap), zend_weakref_key_to_object(obj_key)); } ZEND_HASH_FOREACH_END(); zend_hash_destroy(&ZT_G(global_weakmap)); + + if (ZT_G(zend_test_heap)) { + free(ZT_G(zend_test_heap)); + ZT_G(zend_test_heap) = NULL; + zend_mm_set_heap(ZT_G(zend_orig_heap)); + } + return SUCCESS; } diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index eaed7e2794aeb..cf8ac50bd0629 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -47,6 +47,11 @@ public function returnsThrowable(): Throwable {} static public function variadicTest(string|Iterator ...$elements) : static {} } + class _ZendTestMagicCall + { + public function __call(string $name, array $args): mixed {} + } + class _ZendTestChildClass extends _ZendTestClass { public function returnsThrowable(): Exception {} @@ -175,6 +180,8 @@ function zend_test_crash(?string $message = null): void {} #if defined(HAVE_LIBXML) && !defined(PHP_WIN32) function zend_test_override_libxml_global_state(): void {} #endif + + function zend_test_is_pcre_bundled(): bool {} } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 72b89ef33342f..70439ff726164 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 37c6d5e5e28a60b3d1cf89c1a2f82a0196fceae7 */ + * Stub hash: 420711ec6f040d38bde450a169bf1186f8531191 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -109,16 +109,18 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_override_libxml_global ZEND_END_ARG_INFO() #endif -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ZendTestNS2_namespaced_func, 0, 0, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_is_pcre_bundled, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() +#define arginfo_ZendTestNS2_namespaced_func arginfo_zend_test_is_pcre_bundled + #define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_test_void_return #define arginfo_ZendTestNS2_namespaced_aliased_func arginfo_zend_test_void_return #define arginfo_ZendTestNS2_namespaced_deprecated_aliased_func arginfo_zend_test_void_return -#define arginfo_ZendTestNS2_ZendSubNS_namespaced_func arginfo_ZendTestNS2_namespaced_func +#define arginfo_ZendTestNS2_ZendSubNS_namespaced_func arginfo_zend_test_is_pcre_bundled #define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_func arginfo_zend_test_void_return @@ -140,10 +142,15 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestClass_variadicTes ZEND_ARG_VARIADIC_OBJ_TYPE_MASK(0, elements, Iterator, MAY_BE_STRING) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestMagicCall___call, 0, 2, IS_MIXED, 0) + ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, args, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class__ZendTestChildClass_returnsThrowable, 0, 0, Exception, 0) ZEND_END_ARG_INFO() -#define arginfo_class__ZendTestTrait_testMethod arginfo_ZendTestNS2_namespaced_func +#define arginfo_class__ZendTestTrait_testMethod arginfo_zend_test_is_pcre_bundled ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ZendTestParameterAttribute___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, parameter, IS_STRING, 0) @@ -208,6 +215,7 @@ static ZEND_FUNCTION(zend_test_crash); #if defined(HAVE_LIBXML) && !defined(PHP_WIN32) static ZEND_FUNCTION(zend_test_override_libxml_global_state); #endif +static ZEND_FUNCTION(zend_test_is_pcre_bundled); static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); @@ -217,6 +225,7 @@ static ZEND_METHOD(_ZendTestClass, __toString); static ZEND_METHOD(_ZendTestClass, returnsStatic); static ZEND_METHOD(_ZendTestClass, returnsThrowable); static ZEND_METHOD(_ZendTestClass, variadicTest); +static ZEND_METHOD(_ZendTestMagicCall, __call); static ZEND_METHOD(_ZendTestChildClass, returnsThrowable); static ZEND_METHOD(_ZendTestTrait, testMethod); static ZEND_METHOD(ZendTestParameterAttribute, __construct); @@ -265,6 +274,7 @@ static const zend_function_entry ext_functions[] = { #if defined(HAVE_LIBXML) && !defined(PHP_WIN32) ZEND_FE(zend_test_override_libxml_global_state, arginfo_zend_test_override_libxml_global_state) #endif + ZEND_FE(zend_test_is_pcre_bundled, arginfo_zend_test_is_pcre_bundled) ZEND_NS_FALIAS("ZendTestNS2", namespaced_func, ZendTestNS2_namespaced_func, arginfo_ZendTestNS2_namespaced_func) ZEND_NS_DEP_FALIAS("ZendTestNS2", namespaced_deprecated_func, ZendTestNS2_namespaced_deprecated_func, arginfo_ZendTestNS2_namespaced_deprecated_func) ZEND_NS_FALIAS("ZendTestNS2", namespaced_aliased_func, zend_test_void_return, arginfo_ZendTestNS2_namespaced_aliased_func) @@ -292,6 +302,12 @@ static const zend_function_entry class__ZendTestClass_methods[] = { }; +static const zend_function_entry class__ZendTestMagicCall_methods[] = { + ZEND_ME(_ZendTestMagicCall, __call, arginfo_class__ZendTestMagicCall___call, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + + static const zend_function_entry class__ZendTestChildClass_methods[] = { ZEND_ME(_ZendTestChildClass, returnsThrowable, arginfo_class__ZendTestChildClass_returnsThrowable, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -482,6 +498,16 @@ static zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_e return class_entry; } +static zend_class_entry *register_class__ZendTestMagicCall(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "_ZendTestMagicCall", class__ZendTestMagicCall_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + + return class_entry; +} + static zend_class_entry *register_class__ZendTestChildClass(zend_class_entry *class_entry__ZendTestClass) { zend_class_entry ce, *class_entry; diff --git a/ext/zend_test/tests/internal_magic_call.phpt b/ext/zend_test/tests/internal_magic_call.phpt new file mode 100644 index 0000000000000..2139ddeb5004a --- /dev/null +++ b/ext/zend_test/tests/internal_magic_call.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-12835: call->extra_named_params leaks on internal __call +--EXTENSIONS-- +zend_test +--FILE-- +test('a', 'b', c: 'c')); +?> +--EXPECT-- +array(2) { + [0]=> + string(4) "test" + [1]=> + array(3) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" + ["c"]=> + string(1) "c" + } +} diff --git a/ext/zend_test/tests/opline_dangling.phpt b/ext/zend_test/tests/opline_dangling.phpt new file mode 100644 index 0000000000000..3b27b544ca34f --- /dev/null +++ b/ext/zend_test/tests/opline_dangling.phpt @@ -0,0 +1,35 @@ +--TEST-- +possible segfault in `ZEND_BIND_STATIC` +--DESCRIPTION-- +https://github.com/php/php-src/pull/12758 +--EXTENSIONS-- +zend_test +--ENV-- +USE_ZEND_ALLOC=1 +--INI-- +zend_test.observe_opline_in_zendmm=1 +--FILE-- + +--EXPECT-- +int(1) +string(1) "x" +int(1) +int(5) +Done. diff --git a/ext/zend_test/tests/opline_dangling_02.phpt b/ext/zend_test/tests/opline_dangling_02.phpt new file mode 100644 index 0000000000000..585a9c8395b59 --- /dev/null +++ b/ext/zend_test/tests/opline_dangling_02.phpt @@ -0,0 +1,37 @@ +--TEST-- +possible segfault in `ZEND_FUNC_GET_ARGS` +--EXTENSIONS-- +zend_test +--ENV-- +USE_ZEND_ALLOC=1 +--INI-- +zend_test.observe_opline_in_zendmm=1 +--FILE-- + +--EXPECT-- +int(1) +string(1) "x" +int(1) +array(2) { + [0]=> + string(6) "string" + [1]=> + int(0) +} +Done. diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 095fa23fe7746..108b851091ee4 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -1763,7 +1763,7 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /* basename = php_basename(Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file), NULL, 0); file_stripped = ZSTR_VAL(basename); file_stripped_len = ZSTR_LEN(basename); - } else if (opts.remove_path && strstr(Z_STRVAL_P(zval_file), opts.remove_path) != NULL) { + } else if (opts.remove_path && !memcmp(Z_STRVAL_P(zval_file), opts.remove_path, opts.remove_path_len)) { if (IS_SLASH(Z_STRVAL_P(zval_file)[opts.remove_path_len])) { file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len + 1; file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len - 1; diff --git a/ext/zip/tests/bug_gh12661.phpt b/ext/zip/tests/bug_gh12661.phpt new file mode 100644 index 0000000000000..993299b8657f2 --- /dev/null +++ b/ext/zip/tests/bug_gh12661.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug GH-12661 (Inconsistency in ZipArchive::addGlob 'remove_path' Option Behavior) +--EXTENSIONS-- +zip +--FILE-- +open($file, ZipArchive::CREATE | ZipArchive::OVERWRITE); +$zip->addGlob(__FILE__, 0, ['remove_path' => 'bug_']); // unchanged (bug is not a prefix) +$zip->addGlob(__FILE__, 0, ['remove_path' => dirname(__DIR__)]); +verify_entries($zip, [__FILE__, basename(__DIR__) . DIRECTORY_SEPARATOR . basename(__FILE__)]); +$zip->close(); + +?> +Done +--CLEAN-- + +--EXPECT-- +Done diff --git a/ext/zlib/tests/gzcompress_basic1.phpt b/ext/zlib/tests/gzcompress_basic1.phpt index ec5f554153dab..b5ad22341ed74 100644 --- a/ext/zlib/tests/gzcompress_basic1.phpt +++ b/ext/zlib/tests/gzcompress_basic1.phpt @@ -2,6 +2,8 @@ Test gzcompress() function : basic functionality --EXTENSIONS-- zlib +--SKIPIF-- + --FILE-- --FILE-- --FILE-- fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) { - /* flush to commit data written to the fopencookie FILE* */ - fflush(stream->stdiocast); + /* flush can call seek internally so we need to prevent an infinite loop */ + if (!stream->fclose_stdiocast_flush_in_progress) { + stream->fclose_stdiocast_flush_in_progress = 1; + /* flush to commit data written to the fopencookie FILE* */ + fflush(stream->stdiocast); + stream->fclose_stdiocast_flush_in_progress = 0; + } } /* handle the case where we are in the buffer */ diff --git a/run-tests.php b/run-tests.php index 19335cbf697a3..bb422e41c0fe4 100755 --- a/run-tests.php +++ b/run-tests.php @@ -2804,10 +2804,44 @@ function run_test(string $php, $file, array $env): string return $restype[0] . 'ED'; } +function is_flaky(TestFile $test): bool +{ + if ($test->hasSection('FLAKY')) { + return true; + } + if (!$test->hasSection('FILE')) { + return false; + } + $file = $test->getSection('FILE'); + $flaky_functions = [ + 'disk_free_space', + 'hrtime', + 'microtime', + 'sleep', + 'usleep', + ]; + $regex = '(\b(' . implode('|', $flaky_functions) . ')\()i'; + return preg_match($regex, $file) === 1; +} + +function is_flaky_output(string $output): bool +{ + $messages = [ + '404: page not found', + 'address already in use', + 'connection refused', + 'deadlock', + 'mailbox already exists', + 'timed out', + ]; + $regex = '(\b(' . implode('|', $messages) . ')\b)i'; + return preg_match($regex, $output) === 1; +} + function error_may_be_retried(TestFile $test, string $output): bool { - return preg_match('((timed out)|(connection refused)|(404: page not found)|(address already in use)|(mailbox already exists))i', $output) === 1 - || $test->hasSection('FLAKY'); + return is_flaky_output($output) + || is_flaky($test); } /** diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c index f0d869444afce..f698753cf4c65 100644 --- a/sapi/fpm/fpm/fpm_status.c +++ b/sapi/fpm/fpm/fpm_status.c @@ -56,7 +56,7 @@ int fpm_status_export_to_zval(zval *status) scoreboard_p = fpm_scoreboard_acquire(NULL, 1); if (!scoreboard_p) { - zlog(ZLOG_NOTICE, "[pool %s] status: scoreboard already in use.", scoreboard_p->pool); + zlog(ZLOG_NOTICE, "[pool (unknown)] status: scoreboard already in use."); return -1; } diff --git a/sapi/fpm/tests/gh12621.phpt b/sapi/fpm/tests/gh12621.phpt new file mode 100644 index 0000000000000..0ee64fbe415bd --- /dev/null +++ b/sapi/fpm/tests/gh12621.phpt @@ -0,0 +1,46 @@ +--TEST-- +GH-12621 (browscap segmentation fault when configured with php_admin_value) +--SKIPIF-- + +--FILE-- +browser_name_pattern; +var_dump(\$cv); +EOT; + +$tester = new FPM\Tester($cfg, $code); +$tester->start(); +$tester->expectLogStartNotices(); +echo $tester + ->request() + ->getBody(); +$tester->terminate(); +$tester->close(); + +?> +--EXPECT-- +string(14) "*Konqueror/2.*" +--CLEAN-- + diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 2464e39e5683c..ffc40cb0c9686 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -408,6 +408,7 @@ PHPDBG_COMMAND(exec) /* {{{ */ if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) { if (PHPDBG_G(in_execution)) { if (phpdbg_ask_user_permission("Do you really want to stop execution to set a new execution context?") == FAILURE) { + free(res); return FAILURE; } } @@ -441,6 +442,7 @@ PHPDBG_COMMAND(exec) /* {{{ */ phpdbg_compile(); } else { + free(res); phpdbg_notice("Execution context not changed"); } } else { diff --git a/sapi/phpdbg/tests/gh12675.phpt b/sapi/phpdbg/tests/gh12675.phpt new file mode 100644 index 0000000000000..167e68595df31 --- /dev/null +++ b/sapi/phpdbg/tests/gh12675.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-12675 (MEMORY_LEAK in phpdbg_prompt.c) +--INI-- +opcache.enable=0 +--PHPDBG-- +ev file_put_contents("gh12675_1.tmp", " 24 +prompt> 16 +prompt> [Cannot stat nonexistent.php, ensure the file exists] +prompt> [Set execution context: %sgh12675_1.tmp] +[Successful compilation of %sgh12675_1.tmp] +prompt> [Execution context not changed] +prompt> [Breakpoint #0 added at %sgh12675_1.tmp:2] +prompt> hi +[Breakpoint #0 at %sgh12675_1.tmp:2, hits: 1] +>00002: echo 2; +prompt> Do you really want to stop execution to set a new execution context? (type y or n): prompt> +--CLEAN-- + diff --git a/travis/test.sh b/travis/test.sh index 8aaab2d13417d..92253042751e4 100755 --- a/travis/test.sh +++ b/travis/test.sh @@ -4,9 +4,10 @@ set -ex # ARM64 CI reports nproc=32, which is excessive. if [ -z "$ARM64" ]; then export JOBS=$(nproc); else export JOBS=16; fi +export SKIP_SLOW_TESTS=1 export SKIP_IO_CAPTURE_TESTS=1 ./sapi/cli/php run-tests.php -P \ - -g "FAIL,BORK,LEAK" --offline --show-diff --show-slow 1000 \ + -g "FAIL,SKIP,BORK,LEAK" --offline --show-diff --show-slow 1000 \ --no-progress \ --set-timeout 120 -j$JOBS \ -d extension=`pwd`/modules/zend_test.so \