diff --git a/.circleci/config.yml b/.circleci/config.yml index 332751fb53bd0..26834a9392e0c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -184,6 +184,8 @@ jobs: -d opcache.enable_cli=1 \ -d opcache.jit_buffer_size=16M \ -d opcache.jit=tracing \ + -d zend_test.observer.enabled=1 \ + -d zend_test.observer.show_output=0 \ -P -q -x -j2 \ -g FAIL,BORK,LEAK,XLEAK \ --no-progress \ diff --git a/.github/nightly_matrix.php b/.github/nightly_matrix.php index e74508785e219..23d391ffcff85 100644 --- a/.github/nightly_matrix.php +++ b/.github/nightly_matrix.php @@ -70,6 +70,7 @@ function get_matrix_include(array $branches) { 'debug' => true, 'zts' => true, 'configuration_parameters' => "CFLAGS='-DZEND_RC_DEBUG=1 -DPROFITABILITY_CHECKS=0 -DZEND_VERIFY_FUNC_INFO=1'", + 'run_tests_parameters' => '-d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0', 'timeout_minutes' => 360, 'test_function_jit' => true, ]; diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index e08b2539bb70e..e72cd8f77bfd8 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -42,6 +42,7 @@ env: CXX: ccache g++ jobs: LINUX_X64: + if: github.repository == 'php/php-src' || github.event_name == 'pull_request' strategy: fail-fast: false matrix: @@ -98,6 +99,7 @@ jobs: - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files MACOS_DEBUG_NTS: + if: github.repository == 'php/php-src' || github.event_name == 'pull_request' runs-on: macos-12 steps: - name: git checkout @@ -131,6 +133,7 @@ jobs: - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files WINDOWS: + if: github.repository == 'php/php-src' || github.event_name == 'pull_request' name: WINDOWS_X64_ZTS runs-on: windows-2019 env: diff --git a/NEWS b/NEWS index d73bb484d204f..3b7f2e43e9970 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,82 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.2.18 +09 May 2024, PHP 8.2.19 + +- Core: + . Fixed bug GH-13772 (Invalid execute_data->opline pointers in observer fcall + handlers when JIT is enabled). (Bob) + . Fixed bug GH-13931 (Applying zero offset to null pointer in + Zend/zend_opcode.c). (nielsdos) + . Fixed bug GH-13942 (Align the behavior of zend-max-execution-timers with + other timeout implementations). (Kévin Dunglas) + . Fixed bug GH-14003 (Broken cleanup of unfinished calls with callable convert + parameters). (ilutov) + . Fixed bug GH-14013 (Erroneous dnl appended in configure). (Peter Kokot) + . Fixed bug GH-10232 (If autoloading occurs during constant resolution + filename and lineno are identified incorrectly). (ranvis) + . Fixed bug GH-13727 (Missing void keyword). (Peter Kokot) + +- Fibers: + . Fixed bug GH-13903 (ASAN false positive underflow when executing copy()). + (nielsdos) + +- FPM: + . Fixed bug GH-13563 (Setting bool values via env in FPM config fails). + (Jakub Zelenka) + +- Intl: + . Fixed build for icu 74 and onwards. (dunglas) + +- MySQLnd: + . Fix shift out of bounds on 32-bit non-fast-path platforms. (nielsdos) + +- Opcache: + . Fixed incorrect assumptions across compilation units for static calls. + (ilutov) + +- OpenSSL: + . Fixed bug GH-10495 (feof on OpenSSL stream hangs indefinitely). + (Jakub Zelenka) + +- PDO SQLite: + . Fix GH-13984 (Buffer size is now checked before memcmp). (Saki Takamachi) + . Fix GH-13998 (Manage refcount of agg_context->val correctly). + (Saki Takamachi) + +- Phar: + . Fixed bug GH-13836 (Renaming a file in a Phar to an already existing + filename causes a NULL pointer dereference). (nielsdos) + . Fixed bug GH-13833 (Applying zero offset to null pointer in zend_hash.c). + (nielsdos) + . Fix potential NULL pointer dereference before calling EVP_SignInit. (icy17) + +- PHPDBG: + . Fixed bug GH-13827 (Null pointer access of type 'zval' in phpdbg_frame). + (nielsdos) + +- Posix: + . Fix usage of reentrant functions in ext/posix. (Arnaud) + +- Session: + . Fixed bug GH-13856 (Member access within null pointer of type 'ps_files' in + ext/session/mod_files.c). (nielsdos) + . Fixed bug GH-13891 (memleak and segfault when using ini_set with + session.trans_sid_hosts). (nielsdos, kamil-tekiela) + . Fixed buffer _read/_write size limit on windows for the file mode. (David Carlier) + +- Streams: + . Fixed file_get_contents() on Windows fails with "errno=22 Invalid + argument". (Damian Wójcik) + . Fixed bug GH-13264 (Part 1 - Memory leak on stream filter failure). + (Jakub Zelenka) + . Fixed bug GH-13860 (Incorrect PHP_STREAM_OPTION_CHECK_LIVENESS case in + ext/openssl/xp_ssl.c - causing use of dead socket). (nielsdos) + . Fixed bug GH-11678 (Build fails on musl 1.2.4 - lfs64). (Arnaud) + +- Treewide: + . Fix gcc-14 Wcalloc-transposed-args warnings. (Cristian Rodríguez) + +11 Apr 2024, PHP 8.2.18 - Core: . Fixed bug GH-13612 (Corrupted memory in destructor with weak references). @@ -15,7 +91,7 @@ PHP NEWS . Fix phpdoc for DOMDocument load methods. (VincentLanglet) - FPM - . Fix incorrect check in fpm_shm_free(). (nielsdos) + . Fixed incorrect check in fpm_shm_free(). (nielsdos) - GD: . Fixed bug GH-12019 (add GDLIB_CFLAGS in feature tests). (Michael Orlitzky) @@ -62,6 +138,12 @@ PHP NEWS (SakiTakamachi) . Fixed bug GH-13203 (file_put_contents fail on strings over 4GB on Windows). (divinity76) + . Fixed bug GHSA-pc52-254m-w9w7 (Command injection via array-ish $command + parameter of proc_open). (CVE-2024-1874) (Jakub Zelenka) + . Fixed bug GHSA-wpj3-hf5j-x4v4 (__Host-/__Secure- cookie bypass due to + partial CVE-2022-31629 fix). (CVE-2024-2756) (nielsdos) + . Fixed bug GHSA-h746-cjrr-wfmr (password_verify can erroneously return true, + opening ATO risk). (CVE-2024-3096) (Jakub Zelenka) - XML: . Fixed bug GH-13517 (Multiple test failures when building with @@ -138,7 +220,7 @@ PHP NEWS (David Carlier). - PDO_Firebird: - . Fix GH-13119 (Changed to convert float and double values ​​into strings using + . Fix GH-13119 (Changed to convert float and double values into strings using `H` format). (SakiTakamachi) - Phar: diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index 681173f094d40..600719cc6ce7a 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -5051,6 +5051,9 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op return 1; } } + if (t1 & (MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_REF)) { + return 1; + } return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_TRUE|MAY_BE_FALSE|MAY_BE_STRING|MAY_BE_LONG|MAY_BE_DOUBLE)) || opline->op2_type == IS_UNUSED || (t2 & (MAY_BE_UNDEF|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); case ZEND_ASSIGN_OBJ: diff --git a/Zend/tests/gh10232.phpt b/Zend/tests/gh10232.phpt new file mode 100644 index 0000000000000..8e8d7ff86b5c6 --- /dev/null +++ b/Zend/tests/gh10232.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-10232 (Weird behaviour when a file is autoloaded in assignment of a constant) +--FILE-- +getLine(), "\n"; + require_once __DIR__ . '/gh10232/constant_def.inc'; +}, true); + + +class ConstantRef +{ + public const VALUE = ConstantDef::VALUE; +} + +ConstantRef::VALUE; + +?> +--EXPECTF-- +Notice: 7 in %sgh10232.php on line 7 +Exception on line 8 + +Notice: constant_def.inc in %sconstant_def.inc on line 3 +Exception in constant_def.inc on line 4 + +Notice: required.inc in %srequired.inc on line 3 +Exception in required.inc on line 4 diff --git a/Zend/tests/gh10232/constant_def.inc b/Zend/tests/gh10232/constant_def.inc new file mode 100644 index 0000000000000..22e469af63828 --- /dev/null +++ b/Zend/tests/gh10232/constant_def.inc @@ -0,0 +1,12 @@ +getFile()), ' on line ', $ex->getLine(), "\n"; + +require_once 'required.inc'; // The script of the same directory. + +class ConstantDef +{ + const VALUE = true; +} diff --git a/Zend/tests/gh10232/required.inc b/Zend/tests/gh10232/required.inc new file mode 100644 index 0000000000000..d5ff90da0211c --- /dev/null +++ b/Zend/tests/gh10232/required.inc @@ -0,0 +1,5 @@ +getFile()), ' on line ', $ex->getLine(), "\n"; diff --git a/Zend/tests/gh10346.phpt b/Zend/tests/gh10346.phpt index 74fce28e2307c..37d46b91317ff 100644 --- a/Zend/tests/gh10346.phpt +++ b/Zend/tests/gh10346.phpt @@ -6,6 +6,7 @@ Florian Sowade zend_test --INI-- zend_test.observer.enabled=1 +zend_test.observer.show_output=1 zend_test.observer.observe_all=1 --FILE-- +--EXPECTF-- +Fatal error: 'break' not in the 'loop' or 'switch' context in %s on line %d +int(4) diff --git a/Zend/tests/gh14003.phpt b/Zend/tests/gh14003.phpt new file mode 100644 index 0000000000000..92a6c5919ab5b --- /dev/null +++ b/Zend/tests/gh14003.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-14003: Missing handling of CALLABLE_CONVERT in cleanup_unfinished_calls() +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Exception: Test in %s:%d +Stack trace: +#0 [internal function]: foo('a') +#1 %s(%d): array_map(Object(Closure), Array) +#2 {main} + thrown in %s on line %d diff --git a/Zend/tests/gh7771_3.phpt b/Zend/tests/gh7771_3.phpt index f6780814b89b4..e44a01a8aec74 100644 --- a/Zend/tests/gh7771_3.phpt +++ b/Zend/tests/gh7771_3.phpt @@ -12,5 +12,5 @@ spl_autoload_register(function($class) use ($classlist) { var_dump(D::HW); ?> --EXPECTF-- -Fatal error: Constant expression contains invalid operations in %sgh7771_3.php(7) : eval()'d code(1) : eval()'d code on line 1 +Fatal error: Constant expression contains invalid operations in %sgh7771_3.php(7) : eval()'d code on line 1 diff --git a/Zend/zend.h b/Zend/zend.h index 12a467ee8a44e..95bc49df8db49 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.2.18-dev" +#define ZEND_VERSION "4.2.19" #define ZEND_ENGINE_3 diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index cba90112cfc18..e7f9ed8f000a2 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3996,6 +3996,27 @@ static bool fbc_is_finalized(zend_function *fbc) { return !ZEND_USER_CODE(fbc->type) || (fbc->common.fn_flags & ZEND_ACC_DONE_PASS_TWO); } +static bool zend_compile_ignore_class(zend_class_entry *ce, zend_string *filename) +{ + if (ce->type == ZEND_INTERNAL_CLASS) { + return CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES; + } else { + return (CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) + && ce->info.user.filename != filename; + } +} + +static bool zend_compile_ignore_function(zend_function *fbc, zend_string *filename) +{ + if (fbc->type == ZEND_INTERNAL_FUNCTION) { + return CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS; + } else { + return (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS) + || ((CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) + && fbc->op_array.filename != filename); + } +} + static zend_result zend_try_compile_ct_bound_init_user_func(zend_ast *name_ast, uint32_t num_args) /* {{{ */ { zend_string *name, *lcname; @@ -4010,11 +4031,9 @@ static zend_result zend_try_compile_ct_bound_init_user_func(zend_ast *name_ast, lcname = zend_string_tolower(name); fbc = zend_hash_find_ptr(CG(function_table), lcname); - if (!fbc || !fbc_is_finalized(fbc) - || (fbc->type == ZEND_INTERNAL_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS)) - || (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)) - || (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) && fbc->op_array.filename != CG(active_op_array)->filename) - ) { + if (!fbc + || !fbc_is_finalized(fbc) + || zend_compile_ignore_function(fbc, CG(active_op_array)->filename)) { zend_string_release_ex(lcname, 0); return FAILURE; } @@ -4538,11 +4557,9 @@ static void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{ return; } - if (!fbc || !fbc_is_finalized(fbc) - || (fbc->type == ZEND_INTERNAL_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS)) - || (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)) - || (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) && fbc->op_array.filename != CG(active_op_array)->filename) - ) { + if (!fbc + || !fbc_is_finalized(fbc) + || zend_compile_ignore_function(fbc, CG(active_op_array)->filename)) { zend_string_release_ex(lcname, 0); zend_compile_dynamic_call(result, &name_node, args_ast, ast->lineno); return; @@ -4709,7 +4726,11 @@ static void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type if (opline->op1_type == IS_CONST) { zend_string *lcname = Z_STR_P(CT_CONSTANT(opline->op1) + 1); ce = zend_hash_find_ptr(CG(class_table), lcname); - if (!ce && CG(active_class_entry) + if (ce) { + if (zend_compile_ignore_class(ce, CG(active_op_array)->filename)) { + ce = NULL; + } + } else if (CG(active_class_entry) && zend_string_equals_ci(CG(active_class_entry)->name, lcname)) { ce = CG(active_class_entry); } @@ -7990,9 +8011,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel) ce->parent_name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD); if (parent_ce - && ((parent_ce->type != ZEND_INTERNAL_CLASS) || !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES)) - && ((parent_ce->type != ZEND_USER_CLASS) || !(CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) || (parent_ce->info.user.filename == ce->info.user.filename))) { - + && !zend_compile_ignore_class(parent_ce, ce->info.user.filename)) { if (zend_try_early_bind(ce, parent_ce, lcname, NULL)) { zend_string_release(lcname); return; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 0df529203c1b9..5a060540db015 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -4104,6 +4104,7 @@ ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_exe case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_CALLABLE_CONVERT: level++; break; case ZEND_INIT_FCALL: @@ -4159,6 +4160,7 @@ ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_exe case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_CALLABLE_CONVERT: level++; break; case ZEND_INIT_FCALL: @@ -4237,6 +4239,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_CALLABLE_CONVERT: level++; break; case ZEND_INIT_FCALL: @@ -4292,6 +4295,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_CALLABLE_CONVERT: level++; break; case ZEND_INIT_FCALL: diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index fa5e13dba2ea8..c7f814138d00d 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1205,9 +1205,15 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * autoload_name = zend_string_copy(name); } + zend_string *previous_filename = EG(filename_override); + zend_long previous_lineno = EG(lineno_override); + EG(filename_override) = NULL; + EG(lineno_override) = -1; zend_exception_save(); ce = zend_autoload(autoload_name, lc_name); zend_exception_restore(); + EG(filename_override) = previous_filename; + EG(lineno_override) = previous_lineno; zend_string_release_ex(autoload_name, 0); zend_hash_del(EG(in_autoload), lc_name); @@ -1518,6 +1524,11 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ struct itimerval t_r; /* timeout requested */ int signo; + // Prevent EINVAL error + if (seconds < 0 || seconds > 999999999) { + seconds = 0; + } + if(seconds) { t_r.it_value.tv_sec = seconds; t_r.it_value.tv_usec = t_r.it_interval.tv_sec = t_r.it_interval.tv_usec = 0; diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index ea91219a43a07..81e6e8832a064 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -62,6 +62,7 @@ #endif #ifdef __SANITIZE_ADDRESS__ +# include # include #endif @@ -257,6 +258,12 @@ static void zend_fiber_stack_free(zend_fiber_stack *stack) void *pointer = (void *) ((uintptr_t) stack->pointer - ZEND_FIBER_GUARD_PAGES * page_size); +#ifdef __SANITIZE_ADDRESS__ + /* If another mmap happens after unmapping, it may trigger the stale stack red zones + * so we have to unpoison it before unmapping. */ + ASAN_UNPOISON_MEMORY_REGION(pointer, stack->size + ZEND_FIBER_GUARD_PAGES * page_size); +#endif + #ifdef ZEND_WIN32 VirtualFree(pointer, 0, MEM_RELEASE); #else diff --git a/Zend/zend_max_execution_timer.c b/Zend/zend_max_execution_timer.c index 48a4d1bd66415..f9f9740fd8a00 100644 --- a/Zend/zend_max_execution_timer.c +++ b/Zend/zend_max_execution_timer.c @@ -71,6 +71,11 @@ void zend_max_execution_timer_settime(zend_long seconds) /* {{{ }*/ timer_t timer = EG(max_execution_timer_timer); + // Prevent EINVAL error + if (seconds < 0 || seconds > 999999999) { + seconds = 0; + } + struct itimerspec its; its.it_value.tv_sec = seconds; its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0; diff --git a/build/libtool.m4 b/build/libtool.m4 index 5b518d50e4ef5..0b9528d7dc7bf 100644 --- a/build/libtool.m4 +++ b/build/libtool.m4 @@ -4636,7 +4636,7 @@ for ac_symprfx in "" "_"; do extern "C" { #endif char nm_test_var; -void nm_test_func(){} +void nm_test_func(void){} #ifdef __cplusplus } #endif diff --git a/build/php_cxx_compile_stdcxx.m4 b/build/php_cxx_compile_stdcxx.m4 index f8e97fce708f0..8f723266b2c4f 100644 --- a/build/php_cxx_compile_stdcxx.m4 +++ b/build/php_cxx_compile_stdcxx.m4 @@ -27,11 +27,11 @@ AC_DEFUN([PHP_CXX_COMPILE_STDCXX], [dnl [$1], [14], [ax_cxx_compile_alternatives="14 1y"], [$1], [17], [ax_cxx_compile_alternatives="17 1z"], [$1], [20], [ax_cxx_compile_alternatives="20"], - [m4_fatal([invalid first argument `$1' to PHP_CXX_COMPILE_STDCXX])])dnl + [m4_fatal([invalid first argument `$1' to PHP_CXX_COMPILE_STDCXX])])[]dnl m4_if([$2], [], [ax_cxx_compile_cxx$1_required=true], [$2], [mandatory], [ax_cxx_compile_cxx$1_required=true], [$2], [optional], [ax_cxx_compile_cxx$1_required=false], - [m4_fatal([invalid third argument `$2' to PHP_CXX_COMPILE_STDCXX])])dnl + [m4_fatal([invalid third argument `$2' to PHP_CXX_COMPILE_STDCXX])])[]dnl AC_LANG_PUSH([C++])dnl ac_success=no diff --git a/configure.ac b/configure.ac index de0eac8498ec8..f3892dbaaad07 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.18-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.2.19],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 4f2bc890a0e7b..5c6ca05f96108 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -2147,7 +2147,7 @@ static zend_result zend_ffi_cdata_get_closure(zend_object *obj, zend_class_entry if (EXPECTED(EG(trampoline).common.function_name == NULL)) { func = &EG(trampoline); } else { - func = ecalloc(sizeof(zend_internal_function), 1); + func = ecalloc(1, sizeof(zend_internal_function)); } func->type = ZEND_INTERNAL_FUNCTION; func->common.arg_flags[0] = 0; @@ -2898,7 +2898,7 @@ static zend_function *zend_ffi_get_func(zend_object **obj, zend_string *name, co if (EXPECTED(EG(trampoline).common.function_name == NULL)) { func = &EG(trampoline); } else { - func = ecalloc(sizeof(zend_internal_function), 1); + func = ecalloc(1, sizeof(zend_internal_function)); } func->common.type = ZEND_INTERNAL_FUNCTION; func->common.arg_flags[0] = 0; diff --git a/ext/ffi/tests/gh12905.phpt b/ext/ffi/tests/gh12905.phpt index adcc32db2907c..2fe9ef0fab86e 100644 --- a/ext/ffi/tests/gh12905.phpt +++ b/ext/ffi/tests/gh12905.phpt @@ -14,6 +14,7 @@ try { --INI-- ffi.enable=1 zend_test.observer.enabled=1 +zend_test.observer.show_output=1 zend_test.observer.observe_all=1 zend_test.observer.show_return_value=0 --FILE-- diff --git a/ext/intl/config.m4 b/ext/intl/config.m4 index dd687bcd97de3..48f5147ca7bbf 100644 --- a/ext/intl/config.m4 +++ b/ext/intl/config.m4 @@ -80,7 +80,16 @@ if test "$PHP_INTL" != "no"; then breakiterator/codepointiterator_methods.cpp" PHP_REQUIRE_CXX() - PHP_CXX_COMPILE_STDCXX(11, mandatory, PHP_INTL_STDCXX) + + AC_MSG_CHECKING([if intl requires -std=gnu++17]) + AS_IF([test "$PKG_CONFIG icu-uc --atleast-version=74"],[ + AC_MSG_RESULT([yes]) + PHP_CXX_COMPILE_STDCXX(17, mandatory, PHP_INTL_STDCXX) + ],[ + AC_MSG_RESULT([no]) + PHP_CXX_COMPILE_STDCXX(11, mandatory, PHP_INTL_STDCXX) + ]) + PHP_INTL_CXX_FLAGS="$INTL_COMMON_FLAGS $PHP_INTL_STDCXX $ICU_CXXFLAGS" case $host_alias in *cygwin*) PHP_INTL_CXX_FLAGS="$PHP_INTL_CXX_FLAGS -D_POSIX_C_SOURCE=200809L" diff --git a/ext/mysqlnd/mysqlnd_portability.h b/ext/mysqlnd/mysqlnd_portability.h index 295ce393a115a..11ebf4d1bf8ae 100644 --- a/ext/mysqlnd/mysqlnd_portability.h +++ b/ext/mysqlnd/mysqlnd_portability.h @@ -215,8 +215,8 @@ typedef union { *(((char *)(T))+1) = (char)(((A) >> 8));\ *(((char *)(T))+2) = (char)(((A) >> 16));\ *(((char *)(T))+3) = (char)(((A) >> 24)); \ - *(((char *)(T))+4) = (char)(((A) >> 32)); } while (0) -#define int8store(T,A) { uint32_t def_temp= (uint32_t) (A), def_temp2= (uint32_t) ((A) >> 32); \ + *(((char *)(T))+4) = sizeof(A) == 4 ? 0 : (char)(((A) >> 32)); } while (0) +#define int8store(T,A) { uint32_t def_temp= (uint32_t) (A), def_temp2= sizeof(A) == 4 ? 0 : (uint32_t) ((A) >> 32); \ int4store((T),def_temp); \ int4store((T+4),def_temp2); \ } diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc index 329eb42507e3e..910105aa5bbff 100644 --- a/ext/opcache/jit/zend_jit_arm64.dasc +++ b/ext/opcache/jit/zend_jit_arm64.dasc @@ -688,7 +688,7 @@ static bool logical_immediate_p(uint64_t value, uint32_t reg_size) | .if ZTS || if (GCC_GLOBAL_REGS) { | LOAD_TSRM_CACHE IP -| MEM_ACCESS_64_WITH_UOFFSET ldr, IP, IP, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg +| ADD_SUB_64_WITH_CONST_32 add, IP, IP, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg || } else { | LOAD_TSRM_CACHE RX | ADD_SUB_64_WITH_CONST_32 add, RX, RX, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg @@ -1935,6 +1935,7 @@ static int zend_jit_leave_throw_stub(dasm_State **Dst) |5: | // opline = EG(exception_op); | LOAD_IP_ADDR_ZTS executor_globals, exception_op, TMP2 + | str IP, EX->opline | // HANDLE_EXCEPTION() | b ->exception_handler } else { @@ -9449,7 +9450,12 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend } if (ZEND_OBSERVER_ENABLED) { - | SAVE_IP + if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) { + ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END); + | SET_EX_OPLINE trace[1].opline, REG0 + } else { + | SAVE_IP + } | mov FCARG1x, FP | EXT_CALL zend_observer_fcall_begin, REG0 } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index d1cbbd6391c53..d083bf47c76d9 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -406,7 +406,7 @@ static size_t tsrm_tls_offset; | .if ZTS || if (GCC_GLOBAL_REGS) { | LOAD_TSRM_CACHE IP -| mov IP, aword [IP + (struct.._offset + offsetof(zend_..struct, field))] +| lea IP, aword [IP + (struct.._offset + offsetof(zend_..struct, field))] || } else { | LOAD_TSRM_CACHE RX | lea RX, aword [RX + (struct.._offset + offsetof(zend_..struct, field))] @@ -1884,6 +1884,7 @@ static int zend_jit_leave_throw_stub(dasm_State **Dst) |5: | // opline = EG(exception_op); | LOAD_IP_ADDR_ZTS executor_globals, exception_op + | mov aword EX->opline, IP | // HANDLE_EXCEPTION() | jmp ->exception_handler } else { @@ -10187,7 +10188,12 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend } if (ZEND_OBSERVER_ENABLED) { - | SAVE_IP + if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) { + ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END); + | SET_EX_OPLINE trace[1].opline, r0 + } else { + | SAVE_IP + } | mov FCARG1a, FP | EXT_CALL zend_observer_fcall_begin, r0 } diff --git a/ext/opcache/tests/gh13712.phpt b/ext/opcache/tests/gh13712.phpt index e770375e33e46..84c931a4f87ef 100644 --- a/ext/opcache/tests/gh13712.phpt +++ b/ext/opcache/tests/gh13712.phpt @@ -5,6 +5,7 @@ opcache zend_test --INI-- zend_test.observer.enabled=1 +zend_test.observer.show_output=1 opcache.enable=1 opcache.enable_cli=1 --FILE-- diff --git a/ext/opcache/tests/jit/gh13772.phpt b/ext/opcache/tests/jit/gh13772.phpt new file mode 100644 index 0000000000000..97fa6536e0ce7 --- /dev/null +++ b/ext/opcache/tests/jit/gh13772.phpt @@ -0,0 +1,26 @@ +--TEST-- +EX(opline) is correctly set for nested JIT user code calls +--EXTENSIONS-- +opcache +zend_test +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +zend_test.observer.enabled=1 +zend_test.observer.observe_all=1 +zend_test.observer.show_output=0 +--FILE-- + +--EXPECT-- +int(61) + diff --git a/ext/opcache/tests/jit/ignored_opcodes.phpt b/ext/opcache/tests/jit/ignored_opcodes.phpt index 39816c5d4b30f..ca0730f8b9466 100644 --- a/ext/opcache/tests/jit/ignored_opcodes.phpt +++ b/ext/opcache/tests/jit/ignored_opcodes.phpt @@ -8,6 +8,7 @@ opcache.jit_buffer_size=1M opcache.jit=function ;opcache.jit_debug=257 zend_test.observer.enabled=1 +zend_test.observer.show_output=1 zend_test.observer.observe_all=1 zend_test.observer.show_opcode_in_user_handler=ZEND_EXIT, ZEND_BEGIN_SILENCE, ZEND_END_SILENCE --EXTENSIONS-- diff --git a/ext/opcache/tests/match/001.phpt b/ext/opcache/tests/match/001.phpt index 37f564b5bbc80..502400681cf12 100644 --- a/ext/opcache/tests/match/001.phpt +++ b/ext/opcache/tests/match/001.phpt @@ -4,6 +4,7 @@ Match expression string jump table opcache.enable=1 opcache.enable_cli=1 opcache.opt_debug_level=0x20000 +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/match/002.phpt b/ext/opcache/tests/match/002.phpt index 3743d6bed7930..8e7102d539120 100644 --- a/ext/opcache/tests/match/002.phpt +++ b/ext/opcache/tests/match/002.phpt @@ -4,6 +4,7 @@ Test match jump table optimizer opcache.enable=1 opcache.enable_cli=1 opcache.opt_debug_level=0x20000 +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/match/003.phpt b/ext/opcache/tests/match/003.phpt index 9e55cbba942c5..24f3cd2612105 100644 --- a/ext/opcache/tests/match/003.phpt +++ b/ext/opcache/tests/match/003.phpt @@ -4,6 +4,7 @@ Match expression long jump table opcache.enable=1 opcache.enable_cli=1 opcache.opt_debug_level=0x20000 +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/match/004.phpt b/ext/opcache/tests/match/004.phpt index 551c9a5d0e1dc..d9d4149b94510 100644 --- a/ext/opcache/tests/match/004.phpt +++ b/ext/opcache/tests/match/004.phpt @@ -4,6 +4,7 @@ Match expression mixed jump table opcache.enable=1 opcache.enable_cli=1 opcache.opt_debug_level=0x20000 +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/coalesce.phpt b/ext/opcache/tests/opt/coalesce.phpt index 66a2e7f827419..f60294aadc236 100644 --- a/ext/opcache/tests/opt/coalesce.phpt +++ b/ext/opcache/tests/opt/coalesce.phpt @@ -5,6 +5,7 @@ opcache.enable=1 opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/dce_001.phpt b/ext/opcache/tests/opt/dce_001.phpt index 81e309fa4967d..5f9b001a5def8 100644 --- a/ext/opcache/tests/opt/dce_001.phpt +++ b/ext/opcache/tests/opt/dce_001.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/dce_002.phpt b/ext/opcache/tests/opt/dce_002.phpt index 2f105fe352b76..44f1fb403c26b 100644 --- a/ext/opcache/tests/opt/dce_002.phpt +++ b/ext/opcache/tests/opt/dce_002.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/dce_003.phpt b/ext/opcache/tests/opt/dce_003.phpt index 5824eae5523ad..22355baa68d86 100644 --- a/ext/opcache/tests/opt/dce_003.phpt +++ b/ext/opcache/tests/opt/dce_003.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/dce_004.phpt b/ext/opcache/tests/opt/dce_004.phpt index b49caceb0d70e..2c7e785e4f536 100644 --- a/ext/opcache/tests/opt/dce_004.phpt +++ b/ext/opcache/tests/opt/dce_004.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/dce_005.phpt b/ext/opcache/tests/opt/dce_005.phpt index add703e966a2b..c413913aedb8e 100644 --- a/ext/opcache/tests/opt/dce_005.phpt +++ b/ext/opcache/tests/opt/dce_005.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/dce_006.phpt b/ext/opcache/tests/opt/dce_006.phpt index 97d2988793907..2596651ed3e91 100644 --- a/ext/opcache/tests/opt/dce_006.phpt +++ b/ext/opcache/tests/opt/dce_006.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/dce_007.phpt b/ext/opcache/tests/opt/dce_007.phpt index 0f4da98d05959..9139e0478ece6 100644 --- a/ext/opcache/tests/opt/dce_007.phpt +++ b/ext/opcache/tests/opt/dce_007.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/dce_008.phpt b/ext/opcache/tests/opt/dce_008.phpt index 0a55d83fb83b6..697e29f1ab309 100644 --- a/ext/opcache/tests/opt/dce_008.phpt +++ b/ext/opcache/tests/opt/dce_008.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/dce_009.phpt b/ext/opcache/tests/opt/dce_009.phpt index ea3032460cf6c..4300fdd1c5c5f 100644 --- a/ext/opcache/tests/opt/dce_009.phpt +++ b/ext/opcache/tests/opt/dce_009.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/gh11245_1.phpt b/ext/opcache/tests/opt/gh11245_1.phpt index eac085ac44025..06d6da1413771 100644 --- a/ext/opcache/tests/opt/gh11245_1.phpt +++ b/ext/opcache/tests/opt/gh11245_1.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=0x7FFFBFFF opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/gh11245_2.phpt b/ext/opcache/tests/opt/gh11245_2.phpt index 8e967bf9f41be..f42da12c52743 100644 --- a/ext/opcache/tests/opt/gh11245_2.phpt +++ b/ext/opcache/tests/opt/gh11245_2.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=0x7FFFBFFF opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/jmp_001.phpt b/ext/opcache/tests/opt/jmp_001.phpt index 23cd2f796a45d..71ff73671e81b 100644 --- a/ext/opcache/tests/opt/jmp_001.phpt +++ b/ext/opcache/tests/opt/jmp_001.phpt @@ -5,6 +5,7 @@ opcache.enable=1 opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/nullsafe_001.phpt b/ext/opcache/tests/opt/nullsafe_001.phpt index f0c317564136e..171ac7190af9d 100644 --- a/ext/opcache/tests/opt/nullsafe_001.phpt +++ b/ext/opcache/tests/opt/nullsafe_001.phpt @@ -4,6 +4,7 @@ Nullsafe basic optimization opcache.enable=1 opcache.enable_cli=1 opcache.opt_debug_level=0x20000 +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_001.phpt b/ext/opcache/tests/opt/sccp_001.phpt index 20869eb624513..727a239e8f2b4 100644 --- a/ext/opcache/tests/opt/sccp_001.phpt +++ b/ext/opcache/tests/opt/sccp_001.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_002.phpt b/ext/opcache/tests/opt/sccp_002.phpt index 7dda1932e0f61..b290d752e7e2c 100644 --- a/ext/opcache/tests/opt/sccp_002.phpt +++ b/ext/opcache/tests/opt/sccp_002.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_003.phpt b/ext/opcache/tests/opt/sccp_003.phpt index 3002efcc4a1d2..4db7fe4d13c56 100644 --- a/ext/opcache/tests/opt/sccp_003.phpt +++ b/ext/opcache/tests/opt/sccp_003.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_004.phpt b/ext/opcache/tests/opt/sccp_004.phpt index 891fa0ed47368..4a0a7598e49c2 100644 --- a/ext/opcache/tests/opt/sccp_004.phpt +++ b/ext/opcache/tests/opt/sccp_004.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_005.phpt b/ext/opcache/tests/opt/sccp_005.phpt index 1f56feee32018..a673d3092de80 100644 --- a/ext/opcache/tests/opt/sccp_005.phpt +++ b/ext/opcache/tests/opt/sccp_005.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_006.phpt b/ext/opcache/tests/opt/sccp_006.phpt index c8b6253e5c725..49754566e0785 100644 --- a/ext/opcache/tests/opt/sccp_006.phpt +++ b/ext/opcache/tests/opt/sccp_006.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_007.phpt b/ext/opcache/tests/opt/sccp_007.phpt index 112b7791910e2..807ce7ed764ac 100644 --- a/ext/opcache/tests/opt/sccp_007.phpt +++ b/ext/opcache/tests/opt/sccp_007.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_008.phpt b/ext/opcache/tests/opt/sccp_008.phpt index f194249d3513b..f1df4b59980d5 100644 --- a/ext/opcache/tests/opt/sccp_008.phpt +++ b/ext/opcache/tests/opt/sccp_008.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_009.phpt b/ext/opcache/tests/opt/sccp_009.phpt index ca5ba96bc0c68..34995a0546e60 100644 --- a/ext/opcache/tests/opt/sccp_009.phpt +++ b/ext/opcache/tests/opt/sccp_009.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_010.phpt b/ext/opcache/tests/opt/sccp_010.phpt index e9dba9978cfa1..e4bf72116604d 100644 --- a/ext/opcache/tests/opt/sccp_010.phpt +++ b/ext/opcache/tests/opt/sccp_010.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_011.phpt b/ext/opcache/tests/opt/sccp_011.phpt index cba27a0f245ae..78455aa0d80bd 100644 --- a/ext/opcache/tests/opt/sccp_011.phpt +++ b/ext/opcache/tests/opt/sccp_011.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_012.phpt b/ext/opcache/tests/opt/sccp_012.phpt index 203de5fa56aa1..dbd5ee4fd003b 100644 --- a/ext/opcache/tests/opt/sccp_012.phpt +++ b/ext/opcache/tests/opt/sccp_012.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_016.phpt b/ext/opcache/tests/opt/sccp_016.phpt index 46154ad9f046c..3e540ea6ce678 100644 --- a/ext/opcache/tests/opt/sccp_016.phpt +++ b/ext/opcache/tests/opt/sccp_016.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_017.phpt b/ext/opcache/tests/opt/sccp_017.phpt index 43cdc2ed2b648..5afc24bf60ce5 100644 --- a/ext/opcache/tests/opt/sccp_017.phpt +++ b/ext/opcache/tests/opt/sccp_017.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_019.phpt b/ext/opcache/tests/opt/sccp_019.phpt index e3453cd257ffc..00c8a34c2c060 100644 --- a/ext/opcache/tests/opt/sccp_019.phpt +++ b/ext/opcache/tests/opt/sccp_019.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_022.phpt b/ext/opcache/tests/opt/sccp_022.phpt index 595e431752748..ffcc48b0dccd9 100644 --- a/ext/opcache/tests/opt/sccp_022.phpt +++ b/ext/opcache/tests/opt/sccp_022.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_024.phpt b/ext/opcache/tests/opt/sccp_024.phpt index 5fd33e2b7e1a4..56be429cc7994 100644 --- a/ext/opcache/tests/opt/sccp_024.phpt +++ b/ext/opcache/tests/opt/sccp_024.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_026.phpt b/ext/opcache/tests/opt/sccp_026.phpt index 6d2108409b07f..3e318a7f75dfe 100644 --- a/ext/opcache/tests/opt/sccp_026.phpt +++ b/ext/opcache/tests/opt/sccp_026.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_031.phpt b/ext/opcache/tests/opt/sccp_031.phpt index 73b5906df64dc..459fb31233d47 100644 --- a/ext/opcache/tests/opt/sccp_031.phpt +++ b/ext/opcache/tests/opt/sccp_031.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/opt/sccp_032.phpt b/ext/opcache/tests/opt/sccp_032.phpt index 9a03fe4e1d576..dac09a7552745 100644 --- a/ext/opcache/tests/opt/sccp_032.phpt +++ b/ext/opcache/tests/opt/sccp_032.phpt @@ -6,6 +6,7 @@ opcache.enable_cli=1 opcache.optimization_level=-1 opcache.opt_debug_level=0x20000 opcache.preload= +zend_test.observer.enabled=0 --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/zend_accelerator_blacklist.c b/ext/opcache/zend_accelerator_blacklist.c index 8ddc9298bf4d3..c4a543e6207bb 100644 --- a/ext/opcache/zend_accelerator_blacklist.c +++ b/ext/opcache/zend_accelerator_blacklist.c @@ -58,7 +58,7 @@ void zend_accel_blacklist_init(zend_blacklist *blacklist) zend_accel_blacklist_shutdown(blacklist); } - blacklist->entries = (zend_blacklist_entry *) calloc(sizeof(zend_blacklist_entry), blacklist->size); + blacklist->entries = (zend_blacklist_entry *) calloc(blacklist->size, sizeof(zend_blacklist_entry)); if (!blacklist->entries) { zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Blacklist initialization: no memory\n"); return; diff --git a/ext/openssl/tests/ServerClientTestCase.inc b/ext/openssl/tests/ServerClientTestCase.inc index 753366df6f4be..a05a4815a0196 100644 --- a/ext/openssl/tests/ServerClientTestCase.inc +++ b/ext/openssl/tests/ServerClientTestCase.inc @@ -26,6 +26,35 @@ function phpt_has_sslv3() { return $result; } +function phpt_extract_tls_records($rawData) { + $records = []; + $offset = 0; + $dataLength = strlen($rawData); + + while ($offset < $dataLength) { + // Ensure there's enough data left for the header. + if ($offset + 5 > $dataLength) { + break; + } + + // Extract the length of the current record. + $length = unpack("n", substr($rawData, $offset + 3, 2))[1]; + + // Check if the total length is within the bounds of the rawData. + if ($offset + 5 + $length > $dataLength) { + break; + } + + // Extract the record and add it to the records array. + $records[] = substr($rawData, $offset, 5 + $length); + + // Move the offset past the current record. + $offset += 5 + $length; + } + + return $records; +} + /** * This is a singleton to let the wait/notify functions work * I know it's horrible, but it's a means to an end diff --git a/ext/openssl/tests/gh10495.phpt b/ext/openssl/tests/gh10495.phpt new file mode 100644 index 0000000000000..7c743d8de50a5 --- /dev/null +++ b/ext/openssl/tests/gh10495.phpt @@ -0,0 +1,117 @@ +--TEST-- +GH-10495: feof hangs indefinitely +--EXTENSIONS-- +openssl +--SKIPIF-- + +--FILE-- + ['verify_peer' => false, 'peer_name' => '%s']]); + + phpt_wait('server'); + phpt_notify('proxy'); + + phpt_wait('proxy'); + $fp = stream_socket_client("tlsv1.2://127.0.0.1:10012", $errornum, $errorstr, 1, STREAM_CLIENT_CONNECT, $context); + + phpt_wait('proxy'); + + $time = microtime(true); + var_dump(feof($fp)); + var_dump(microtime(true) - $time < 0.5); + + var_dump(stream_get_contents($fp, 6)); + + phpt_notify('server'); + phpt_notify('proxy'); +CODE; +$clientCode = sprintf($clientCode, $peerName); + +$serverCode = <<<'CODE' + $context = stream_context_create(['ssl' => ['local_cert' => '%s']]); + + $flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN; + $fp = stream_socket_server("tlsv1.2://127.0.0.1:10011", $errornum, $errorstr, $flags, $context); + phpt_notify(); + + $conn = stream_socket_accept($fp); + fwrite($conn, 'warmup'); + + phpt_wait(); + fclose($conn); +CODE; +$serverCode = sprintf($serverCode, $certFile); + +$proxyCode = <<<'CODE' + phpt_wait(); + + $upstream = stream_socket_client("tcp://127.0.0.1:10011", $errornum, $errorstr, 3000, STREAM_CLIENT_CONNECT); + stream_set_blocking($upstream, false); + + $flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN; + $server = stream_socket_server("tcp://127.0.0.1:10012", $errornum, $errorstr, $flags); + phpt_notify(); + $conn = stream_socket_accept($server); + stream_set_blocking($conn, false); + + $read = [$upstream, $conn]; + $applicationData = false; + while (stream_select($read, $write, $except, 1)) { + foreach ($read as $fp) { + $data = stream_get_contents($fp); + if ($fp === $conn) { + fwrite($upstream, $data); + } else { + foreach (phpt_extract_tls_records($data) as $record) { + if ($record !== '' && $record[0] === chr(23)) { + if (!$applicationData) { + $applicationData = true; + fwrite($conn, $record[0]); + phpt_notify(); + sleep(1); + fwrite($conn, substr($record, 1)); + } else { + fwrite($conn, $record); + } + } else { + fwrite($conn, $record); + } + } + } + } + if (feof($upstream)) { + break; + } + $read = [$upstream, $conn]; + } + + phpt_wait(); +CODE; + +include 'CertificateGenerator.inc'; +$certificateGenerator = new CertificateGenerator(); +$certificateGenerator->saveCaCert($cacertFile); +$certificateGenerator->saveNewCertAsFileWithKey($peerName, $certFile); + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, [ + 'server' => $serverCode, + 'proxy' => $proxyCode, +]); +?> +--CLEAN-- + +--EXPECT-- +bool(false) +bool(true) +string(6) "warmup" diff --git a/ext/openssl/tests/gh13860.phpt b/ext/openssl/tests/gh13860.phpt new file mode 100644 index 0000000000000..c7c0c40a15760 --- /dev/null +++ b/ext/openssl/tests/gh13860.phpt @@ -0,0 +1,51 @@ +--TEST-- +GH-13860 (Incorrect PHP_STREAM_OPTION_CHECK_LIVENESS case in ext/openssl/xp_ssl.c - causing use of dead socket) +--EXTENSIONS-- +openssl +--SKIPIF-- + +--FILE-- +run($clientCode, $serverCode); +?> +--EXPECT-- +bool(true) diff --git a/ext/openssl/tests/openssl_error_string_basic.phpt b/ext/openssl/tests/openssl_error_string_basic.phpt index 18e06b30bb447..4b5ca9fd9c042 100644 --- a/ext/openssl/tests/openssl_error_string_basic.phpt +++ b/ext/openssl/tests/openssl_error_string_basic.phpt @@ -6,7 +6,6 @@ openssl = 0x30000000) die('skip For OpenSSL < 3.0'); ?> ---XFAIL-- --FILE-- = 3.0'); ?> ---XFAIL-- --FILE-- getMessage() . \PHP_EOL; } -var_dump(openssl_private_decrypt($encrypted, $output5, array($privkey, ""))); +var_dump(openssl_private_decrypt($encrypted, $output5, array($privkey, ""), OPENSSL_PKCS1_OAEP_PADDING)); var_dump($output5); ?> --EXPECTF-- diff --git a/ext/openssl/tests/openssl_x509_parse_basic.phpt b/ext/openssl/tests/openssl_x509_parse_basic.phpt index f9181dd65d5a3..ef63f0f85f497 100644 --- a/ext/openssl/tests/openssl_x509_parse_basic.phpt +++ b/ext/openssl/tests/openssl_x509_parse_basic.phpt @@ -2,6 +2,10 @@ openssl_x509_parse() tests --EXTENSIONS-- openssl +--SKIPIF-- += 0x30200000) die('skip For OpenSSL < 3.2'); +?> --FILE-- = 3.2'); +?> +--FILE-- + +--EXPECTF-- +bool(true) +array(16) { + ["name"]=> + string(96) "/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net" + ["subject"]=> + array(5) { + ["C"]=> + string(2) "BR" + ["ST"]=> + string(17) "Rio Grande do Sul" + ["L"]=> + string(12) "Porto Alegre" + ["CN"]=> + string(21) "Henrique do N. Angelo" + ["emailAddress"]=> + string(16) "hnangelo@php.net" + } + ["hash"]=> + string(8) "%s" + ["issuer"]=> + array(5) { + ["C"]=> + string(2) "BR" + ["ST"]=> + string(17) "Rio Grande do Sul" + ["L"]=> + string(12) "Porto Alegre" + ["CN"]=> + string(21) "Henrique do N. Angelo" + ["emailAddress"]=> + string(16) "hnangelo@php.net" + } + ["version"]=> + int(2) + ["serialNumber"]=> + string(20) "12593567369101004962" + ["serialNumberHex"]=> + string(16) "AEC556CC723750A2" + ["validFrom"]=> + string(13) "080630102843Z" + ["validTo"]=> + string(13) "080730102843Z" + ["validFrom_time_t"]=> + int(1214821723) + ["validTo_time_t"]=> + int(1217413723) + ["signatureTypeSN"]=> + string(8) "RSA-SHA1" + ["signatureTypeLN"]=> + string(21) "sha1WithRSAEncryption" + ["signatureTypeNID"]=> + int(65) + ["purposes"]=> + array(10) { + [1]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(9) "sslclient" + } + [2]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(9) "sslserver" + } + [3]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(11) "nssslserver" + } + [4]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(9) "smimesign" + } + [5]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(12) "smimeencrypt" + } + [6]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(7) "crlsign" + } + [7]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(3) "any" + } + [8]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(10) "ocsphelper" + } + [9]=> + array(3) { + [0]=> + bool(false) + [1]=> + bool(true) + [2]=> + string(13) "timestampsign" + } + [10]=> + array(3) { + [0]=> + bool(false) + [1]=> + bool(true) + [2]=> + string(8) "codesign" + } + } + ["extensions"]=> + array(3) { + ["subjectKeyIdentifier"]=> + string(59) "DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D" + ["authorityKeyIdentifier"]=> + string(%d) "keyid:DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D +DirName:/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net +serial:AE:C5:56:CC:72:37:50:A2%A" + ["basicConstraints"]=> + string(7) "CA:TRUE" + } +} +array(16) { + ["name"]=> + string(96) "/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net" + ["subject"]=> + array(5) { + ["countryName"]=> + string(2) "BR" + ["stateOrProvinceName"]=> + string(17) "Rio Grande do Sul" + ["localityName"]=> + string(12) "Porto Alegre" + ["commonName"]=> + string(21) "Henrique do N. Angelo" + ["emailAddress"]=> + string(16) "hnangelo@php.net" + } + ["hash"]=> + string(8) "%s" + ["issuer"]=> + array(5) { + ["countryName"]=> + string(2) "BR" + ["stateOrProvinceName"]=> + string(17) "Rio Grande do Sul" + ["localityName"]=> + string(12) "Porto Alegre" + ["commonName"]=> + string(21) "Henrique do N. Angelo" + ["emailAddress"]=> + string(16) "hnangelo@php.net" + } + ["version"]=> + int(2) + ["serialNumber"]=> + string(20) "12593567369101004962" + ["serialNumberHex"]=> + string(16) "AEC556CC723750A2" + ["validFrom"]=> + string(13) "080630102843Z" + ["validTo"]=> + string(13) "080730102843Z" + ["validFrom_time_t"]=> + int(1214821723) + ["validTo_time_t"]=> + int(1217413723) + ["signatureTypeSN"]=> + string(8) "RSA-SHA1" + ["signatureTypeLN"]=> + string(21) "sha1WithRSAEncryption" + ["signatureTypeNID"]=> + int(65) + ["purposes"]=> + array(10) { + [1]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(10) "SSL client" + } + [2]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(10) "SSL server" + } + [3]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(19) "Netscape SSL server" + } + [4]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(14) "S/MIME signing" + } + [5]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(17) "S/MIME encryption" + } + [6]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(11) "CRL signing" + } + [7]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(11) "Any Purpose" + } + [8]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(11) "OCSP helper" + } + [9]=> + array(3) { + [0]=> + bool(false) + [1]=> + bool(true) + [2]=> + string(18) "Time Stamp signing" + } + [10]=> + array(3) { + [0]=> + bool(false) + [1]=> + bool(true) + [2]=> + string(12) "Code signing" + } + } + ["extensions"]=> + array(3) { + ["subjectKeyIdentifier"]=> + string(59) "DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D" + ["authorityKeyIdentifier"]=> + string(%d) "keyid:DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D +DirName:/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net +serial:AE:C5:56:CC:72:37:50:A2%A" + ["basicConstraints"]=> + string(7) "CA:TRUE" + } +} diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 2e21c138d6b50..a0db38c20bc02 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -2484,24 +2484,111 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val /* the poll() call was skipped if the socket is non-blocking (or MSG_DONTWAIT is available) and if the timeout is zero */ /* additionally, we don't use this optimization if SSL is active because in that case, we're not using MSG_DONTWAIT */ if (sslsock->ssl_active) { - int n = SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf)); - if (n <= 0) { - int err = SSL_get_error(sslsock->ssl_handle, n); - switch (err) { - case SSL_ERROR_SYSCALL: - alive = php_socket_errno() == EAGAIN; - break; - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - alive = 1; + int retry = 1; + struct timeval start_time; + struct timeval *timeout = NULL; + int began_blocked = sslsock->s.is_blocked; + int has_timeout = 0; + + /* never use a timeout with non-blocking sockets */ + if (began_blocked) { + timeout = &tv; + } + + if (timeout && php_set_sock_blocking(sslsock->s.socket, 0) == SUCCESS) { + sslsock->s.is_blocked = 0; + } + + if (!sslsock->s.is_blocked && timeout && (timeout->tv_sec > 0 || (timeout->tv_sec == 0 && timeout->tv_usec))) { + has_timeout = 1; + /* gettimeofday is not monotonic; using it here is not strictly correct */ + gettimeofday(&start_time, NULL); + } + + /* Main IO loop. */ + do { + struct timeval cur_time, elapsed_time, left_time; + + /* If we have a timeout to check, figure out how much time has elapsed since we started. */ + if (has_timeout) { + gettimeofday(&cur_time, NULL); + + /* Determine how much time we've taken so far. */ + elapsed_time = php_openssl_subtract_timeval(cur_time, start_time); + + /* and return an error if we've taken too long. */ + if (php_openssl_compare_timeval(elapsed_time, *timeout) > 0 ) { + /* If the socket was originally blocking, set it back. */ + if (began_blocked) { + php_set_sock_blocking(sslsock->s.socket, 1); + sslsock->s.is_blocked = 1; + } + sslsock->s.timeout_event = 1; + return PHP_STREAM_OPTION_RETURN_ERR; + } + } + + int n = SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf)); + /* If we didn't do anything on the last loop (or an error) check to see if we should retry or exit. */ + if (n <= 0) { + /* Now, do the IO operation. Don't block if we can't complete... */ + int err = SSL_get_error(sslsock->ssl_handle, n); + switch (err) { + case SSL_ERROR_SYSCALL: + retry = php_socket_errno() == EAGAIN; + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + retry = 1; + break; + default: + /* any other problem is a fatal error */ + retry = 0; + } + + /* Don't loop indefinitely in non-blocking mode if no data is available */ + if (began_blocked == 0 || !has_timeout) { + alive = retry; break; - default: - /* any other problem is a fatal error */ - alive = 0; + } + + /* Now, if we have to wait some time, and we're supposed to be blocking, wait for the socket to become + * available. Now, php_pollfd_for uses select to wait up to our time_left value only... + */ + if (retry) { + /* Now, how much time until we time out? */ + left_time = php_openssl_subtract_timeval(*timeout, elapsed_time); + if (php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI|POLLOUT, has_timeout ? &left_time : NULL) <= 0) { + retry = 0; + alive = 0; + }; + } + } else { + retry = 0; + alive = 1; } + /* Finally, we keep going until there are any data or there is no time to wait. */ + } while (retry); + + if (began_blocked && !sslsock->s.is_blocked) { + // Set it back to blocking + php_set_sock_blocking(sslsock->s.socket, 1); + sslsock->s.is_blocked = 1; + } + } else { +#ifdef PHP_WIN32 + int ret; +#else + ssize_t ret; +#endif + int err; + + ret = recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK|MSG_DONTWAIT); + err = php_socket_errno(); + if (0 == ret || /* the counterpart did properly shutdown */ + (0 > ret && err != EWOULDBLOCK && err != EAGAIN && err != EMSGSIZE)) { /* there was an unrecoverable error */ + alive = 0; } - } else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK|MSG_DONTWAIT) && php_socket_errno() != EAGAIN) { - alive = 0; } } return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR; diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index de5170a35a96b..03b212bf75c1b 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -441,7 +441,6 @@ static int do_callback(struct pdo_sqlite_fci *fc, zval *cb, * the context */ if (agg_context) { if (Z_ISUNDEF(retval)) { - zval_ptr_dtor(&agg_context->val); return FAILURE; } zval_ptr_dtor(Z_REFVAL(agg_context->val)); @@ -751,7 +750,7 @@ static char *make_filename_safe(const char *filename) } return estrdup(filename); } - if (*filename && memcmp(filename, ":memory:", sizeof(":memory:"))) { + if (*filename && strcmp(filename, ":memory:")) { char *fullpath = expand_filepath(filename, NULL); if (!fullpath) { diff --git a/ext/pdo_sqlite/tests/gh13991.phpt b/ext/pdo_sqlite/tests/gh13991.phpt new file mode 100644 index 0000000000000..fa847f8ba5b42 --- /dev/null +++ b/ext/pdo_sqlite/tests/gh13991.phpt @@ -0,0 +1,18 @@ +--TEST-- +Fix GH-13984: Buffer size is now checked before memcmp +--EXTENSIONS-- +pdo_sqlite +--SKIPIF-- + +--FILE-- + true]); +echo 'done!'; +?> +--CLEAN-- + +--EXPECT-- +done! diff --git a/ext/pdo_sqlite/tests/gh13998.phpt b/ext/pdo_sqlite/tests/gh13998.phpt new file mode 100644 index 0000000000000..c87b4acdd214b --- /dev/null +++ b/ext/pdo_sqlite/tests/gh13998.phpt @@ -0,0 +1,25 @@ +--TEST-- +Fix GH-13998: Manage refcount of agg_context->val correctly +--EXTENSIONS-- +pdo_sqlite +--FILE-- +query('CREATE TABLE test (a int, b int)'); +$stmt = $db->query('INSERT INTO test VALUES (1, 1), (2, 2), (3, 3)'); +$db->sqliteCreateAggregate('S', $step, $finalize, 1); + +try { + $db->query('SELECT S(a) FROM test'); +} catch (Exception $e) { + echo 'done!'; +} +?> +--EXPECT-- +done! diff --git a/ext/phar/phar.c b/ext/phar/phar.c index f60b0d6a7c04b..b774f22e2d565 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -1090,6 +1090,9 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, size_t fname_len, ch mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist)); mydata->is_persistent = PHAR_G(persist); + HT_INVALIDATE(&mydata->manifest); + HT_INVALIDATE(&mydata->mounted_dirs); + HT_INVALIDATE(&mydata->virtual_dirs); /* check whether we have meta data, zero check works regardless of byte order */ SAFE_PHAR_GET_32(buffer, endbuffer, len); diff --git a/ext/phar/stream.c b/ext/phar/stream.c index adebe5ab9bd11..ceedbdae35389 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -858,8 +858,9 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from entry->link = entry->tmp = NULL; source = entry; - /* add to the manifest, and then store the pointer to the new guy in entry */ - entry = zend_hash_str_add_mem(&(phar->manifest), ZSTR_VAL(resource_to->path)+1, ZSTR_LEN(resource_to->path)-1, (void **)&new, sizeof(phar_entry_info)); + /* add to the manifest, and then store the pointer to the new guy in entry + * if it already exists, we overwrite the destination like what copy('phar://...', 'phar://...') does. */ + entry = zend_hash_str_update_mem(&(phar->manifest), ZSTR_VAL(resource_to->path)+1, ZSTR_LEN(resource_to->path)-1, (void **)&new, sizeof(phar_entry_info)); entry->filename = estrndup(ZSTR_VAL(resource_to->path)+1, ZSTR_LEN(resource_to->path)-1); if (FAILURE == phar_copy_entry_fp(source, entry, &error)) { diff --git a/ext/phar/tests/gh13833.phpt b/ext/phar/tests/gh13833.phpt new file mode 100644 index 0000000000000..8430bd5e605b2 --- /dev/null +++ b/ext/phar/tests/gh13833.phpt @@ -0,0 +1,47 @@ +--TEST-- +GH-13833 (Applying zero offset to null pointer in zend_hash.c) +--INI-- +phar.require_hash=0 +phar.readonly=0 +--SKIPIF-- + +--FILE-- +"; +$files = array(); +$files['a'] = 'a'; +include 'files/phar_test.inc'; +include $fname; + +$file = ""; +$files['a'] = array('cont' => 'a'); +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +$phar->setMetadata((object) ['my' => 'friend']); +// NOTE: Phar will use the cached value of metadata if setMetaData was called on that Phar path before. +// Save the writes to the phar and use a different file path. +$fname_new = "$fname.copy.phar"; +copy($fname, $fname_new); +try { + new Phar($fname_new); +} catch (UnexpectedValueException $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXTENSIONS-- +phar +--CLEAN-- + +--CREDITS-- +Yuancheng Jiang +Felix De Vliegher +--EXPECTF-- +internal corruption of phar "%sgh13833.phar.copy.phar" (trying to read past buffer end) diff --git a/ext/phar/tests/gh13836.phpt b/ext/phar/tests/gh13836.phpt new file mode 100644 index 0000000000000..d1b79d033e0e8 --- /dev/null +++ b/ext/phar/tests/gh13836.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-13836 (Renaming a file in a Phar to an already existing filename causes a NULL pointer dereference) +--EXTENSIONS-- +phar +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- + +--CLEAN-- + +--EXPECTF-- +bool(true) +bool(false) +object(PharFileInfo)#2 (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%sgh13836.phar/y" + ["fileName":"SplFileInfo":private]=> + string(1) "y" +} diff --git a/ext/phar/util.c b/ext/phar/util.c index 003d579bb9a5e..352819bc9348b 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -1884,6 +1884,13 @@ int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signat } md_ctx = EVP_MD_CTX_create(); + if (md_ctx == NULL) { + EVP_PKEY_free(key); + if (error) { + spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname); + } + return FAILURE; + } siglen = EVP_PKEY_size(key); sigbuf = emalloc(siglen + 1); diff --git a/ext/posix/posix.c b/ext/posix/posix.c index 788fca0b2879d..dbc888a7ea697 100644 --- a/ext/posix/posix.c +++ b/ext/posix/posix.c @@ -447,6 +447,7 @@ PHP_FUNCTION(posix_ttyname) int fd; #if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX) zend_long buflen; + int err; #endif ZEND_PARSE_PARAMETERS_START(1, 1) @@ -465,12 +466,23 @@ PHP_FUNCTION(posix_ttyname) #if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX) buflen = sysconf(_SC_TTY_NAME_MAX); if (buflen < 1) { - RETURN_FALSE; + buflen = 32; } +#if ZEND_DEBUG + /* Test retry logic */ + buflen = 1; +#endif p = emalloc(buflen); - if (ttyname_r(fd, p, buflen)) { - POSIX_G(last_error) = errno; +try_again: + err = ttyname_r(fd, p, buflen); + if (err) { + if (err == ERANGE) { + buflen *= 2; + p = erealloc(p, buflen); + goto try_again; + } + POSIX_G(last_error) = err; efree(p); RETURN_FALSE; } @@ -719,6 +731,7 @@ PHP_FUNCTION(posix_getgrnam) struct group gbuf; long buflen; char *buf; + int err; #endif ZEND_PARSE_PARAMETERS_START(1, 1) @@ -728,19 +741,24 @@ PHP_FUNCTION(posix_getgrnam) #if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX) buflen = sysconf(_SC_GETGR_R_SIZE_MAX); if (buflen < 1) { - RETURN_FALSE; + buflen = 1024; } +#if ZEND_DEBUG + /* Test retry logic */ + buflen = 1; +#endif buf = emalloc(buflen); try_again: g = &gbuf; - if (getgrnam_r(name, g, buf, buflen, &g) || g == NULL) { - if (errno == ERANGE) { + err = getgrnam_r(name, g, buf, buflen, &g); + if (err || g == NULL) { + if (err == ERANGE) { buflen *= 2; buf = erealloc(buf, buflen); goto try_again; } - POSIX_G(last_error) = errno; + POSIX_G(last_error) = err; efree(buf); RETURN_FALSE; } @@ -768,7 +786,7 @@ PHP_FUNCTION(posix_getgrgid) { zend_long gid; #if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX) - int ret; + int err; struct group _g; struct group *retgrptr = NULL; long grbuflen; @@ -784,20 +802,24 @@ PHP_FUNCTION(posix_getgrgid) grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX); if (grbuflen < 1) { - RETURN_FALSE; + grbuflen = 1024; } +#if ZEND_DEBUG + /* Test retry logic */ + grbuflen = 1; +#endif grbuf = emalloc(grbuflen); try_again: - ret = getgrgid_r(gid, &_g, grbuf, grbuflen, &retgrptr); - if (ret || retgrptr == NULL) { - if (errno == ERANGE) { + err = getgrgid_r(gid, &_g, grbuf, grbuflen, &retgrptr); + if (err || retgrptr == NULL) { + if (err == ERANGE) { grbuflen *= 2; grbuf = erealloc(grbuf, grbuflen); goto try_again; } - POSIX_G(last_error) = ret; + POSIX_G(last_error) = err; efree(grbuf); RETURN_FALSE; } @@ -849,6 +871,7 @@ PHP_FUNCTION(posix_getpwnam) struct passwd pwbuf; long buflen; char *buf; + int err; #endif ZEND_PARSE_PARAMETERS_START(1, 1) @@ -858,20 +881,25 @@ PHP_FUNCTION(posix_getpwnam) #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R) buflen = sysconf(_SC_GETPW_R_SIZE_MAX); if (buflen < 1) { - RETURN_FALSE; + buflen = 1024; } +#if ZEND_DEBUG + /* Test retry logic */ + buflen = 1; +#endif buf = emalloc(buflen); - pw = &pwbuf; try_again: - if (getpwnam_r(name, pw, buf, buflen, &pw) || pw == NULL) { - if (errno == ERANGE) { + pw = &pwbuf; + err = getpwnam_r(name, pw, buf, buflen, &pw); + if (err || pw == NULL) { + if (err == ERANGE) { buflen *= 2; buf = erealloc(buf, buflen); goto try_again; } efree(buf); - POSIX_G(last_error) = errno; + POSIX_G(last_error) = err; RETURN_FALSE; } #else @@ -902,7 +930,7 @@ PHP_FUNCTION(posix_getpwuid) struct passwd *retpwptr = NULL; long pwbuflen; char *pwbuf; - int ret; + int err; #endif struct passwd *pw; @@ -913,19 +941,23 @@ PHP_FUNCTION(posix_getpwuid) #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R) pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); if (pwbuflen < 1) { - RETURN_FALSE; + pwbuflen = 1024; } +#if ZEND_DEBUG + /* Test retry logic */ + pwbuflen = 1; +#endif pwbuf = emalloc(pwbuflen); try_again: - ret = getpwuid_r(uid, &_pw, pwbuf, pwbuflen, &retpwptr); - if (ret || retpwptr == NULL) { - if (errno == ERANGE) { + err = getpwuid_r(uid, &_pw, pwbuf, pwbuflen, &retpwptr); + if (err || retpwptr == NULL) { + if (err == ERANGE) { pwbuflen *= 2; pwbuf = erealloc(pwbuf, pwbuflen); goto try_again; } - POSIX_G(last_error) = ret; + POSIX_G(last_error) = err; efree(pwbuf); RETURN_FALSE; } diff --git a/ext/session/mod_files.c b/ext/session/mod_files.c index e640f96f93221..9396f16b93581 100644 --- a/ext/session/mod_files.c +++ b/ext/session/mod_files.c @@ -86,6 +86,7 @@ # ifndef O_NOFOLLOW # define O_NOFOLLOW 0 # endif +#define SESS_FILE_BUF_SIZE(sz) ((unsigned int)(sz > INT_MAX ? INT_MAX : (unsigned int)sz)) #endif typedef struct { @@ -246,7 +247,7 @@ static zend_result ps_files_write(ps_files *data, zend_string *key, zend_string lseek(data->fd, 0, SEEK_SET); #ifdef PHP_WIN32 { - unsigned int to_write = ZSTR_LEN(val) > UINT_MAX ? UINT_MAX : (unsigned int)ZSTR_LEN(val); + unsigned int to_write = SESS_FILE_BUF_SIZE(ZSTR_LEN(val)); char *buf = ZSTR_VAL(val); int wrote; @@ -255,7 +256,7 @@ static zend_result ps_files_write(ps_files *data, zend_string *key, zend_string n += wrote; buf = wrote > -1 ? buf + wrote : 0; - to_write = wrote > -1 ? (ZSTR_LEN(val) - n > UINT_MAX ? UINT_MAX : (unsigned int)(ZSTR_LEN(val) - n)): 0; + to_write = wrote > -1 ? SESS_FILE_BUF_SIZE(ZSTR_LEN(val) - n) : 0; } while(wrote > 0); } @@ -493,7 +494,7 @@ PS_READ_FUNC(files) lseek(data->fd, 0, SEEK_SET); #ifdef PHP_WIN32 { - unsigned int to_read = ZSTR_LEN(*val) > UINT_MAX ? UINT_MAX : (unsigned int)ZSTR_LEN(*val); + unsigned int to_read = SESS_FILE_BUF_SIZE(ZSTR_LEN(*val)); char *buf = ZSTR_VAL(*val); int read_in; @@ -502,7 +503,7 @@ PS_READ_FUNC(files) n += read_in; buf = read_in > -1 ? buf + read_in : 0; - to_read = read_in > -1 ? (ZSTR_LEN(*val) - n > UINT_MAX ? UINT_MAX : (unsigned int)(ZSTR_LEN(*val) - n)): 0; + to_read = read_in > -1 ? SESS_FILE_BUF_SIZE(ZSTR_LEN(*val) - n) : 0; } while(read_in > 0); diff --git a/ext/session/mod_user_class.c b/ext/session/mod_user_class.c index d5b71da52c282..853db659887be 100644 --- a/ext/session/mod_user_class.c +++ b/ext/session/mod_user_class.c @@ -47,8 +47,6 @@ PHP_METHOD(SessionHandler, open) PS_SANITY_CHECK; - PS(mod_user_is_open) = 1; - zend_try { ret = PS(default_mod)->s_open(&PS(mod_data), save_path, session_name); } zend_catch { @@ -56,6 +54,10 @@ PHP_METHOD(SessionHandler, open) zend_bailout(); } zend_end_try(); + if (SUCCESS == ret) { + PS(mod_user_is_open) = 1; + } + RETURN_BOOL(SUCCESS == ret); } /* }}} */ diff --git a/ext/session/tests/gh13856.phpt b/ext/session/tests/gh13856.phpt new file mode 100644 index 0000000000000..a6d9fa0eaedb7 --- /dev/null +++ b/ext/session/tests/gh13856.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-13856 (Member access within null pointer of type 'ps_files' in ext/session/mod_files.c) +--EXTENSIONS-- +session +--INI-- +session.save_handler=files +open_basedir=. +error_reporting=E_ALL +--FILE-- + +--EXPECTF-- +Warning: SessionHandler::open(): open_basedir restriction in effect. File(%s) is not within the allowed path(s): (.) in %s on line %d + +Warning: SessionHandler::close(): Parent session handler is not open in %s on line %d + +Warning: session_start(): Failed to initialize storage module: user (path: ) in %s on line %d diff --git a/ext/session/tests/gh13891.phpt b/ext/session/tests/gh13891.phpt new file mode 100644 index 0000000000000..7df9bffa770bc --- /dev/null +++ b/ext/session/tests/gh13891.phpt @@ -0,0 +1,17 @@ +--TEST-- +GH-13891 (memleak and segfault when using ini_set with session.trans_sid_hosts) +--INI-- +session.use_cookies=0 +session.use_only_cookies=0 +session.use_trans_sid=1 +session.trans_sid_hosts=php.net +--EXTENSIONS-- +session +--SKIPIF-- + +--FILE-- + +--EXPECT-- diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 73ba905f9c324..8183398a8d322 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -219,7 +219,7 @@ int inet_ntoa_lock = 0; static int php_open_listen_sock(php_socket *sock, int port, int backlog) /* {{{ */ { - struct sockaddr_in la; + struct sockaddr_in la = {0}; struct hostent *hp; #ifndef PHP_WIN32 diff --git a/ext/standard/password.c b/ext/standard/password.c index 81117f17b5bcd..7056f1f85c036 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -180,6 +180,11 @@ static zend_string* php_password_bcrypt_hash(const zend_string *password, zend_a zval *zcost; zend_long cost = PHP_PASSWORD_BCRYPT_COST; + if (memchr(ZSTR_VAL(password), '\0', ZSTR_LEN(password))) { + zend_value_error("Bcrypt password must not contain null character"); + return NULL; + } + if (options && (zcost = zend_hash_str_find(options, "cost", sizeof("cost")-1)) != NULL) { cost = zval_get_long(zcost); } diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 866c7a3c896e2..26bbe0afa3ee0 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -492,11 +492,32 @@ static void append_backslashes(smart_str *str, size_t num_bs) } } -/* See https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments */ -static void append_win_escaped_arg(smart_str *str, zend_string *arg) +const char *special_chars = "()!^\"<>&|%"; + +static bool is_special_character_present(const zend_string *arg) +{ + for (size_t i = 0; i < ZSTR_LEN(arg); ++i) { + if (strchr(special_chars, ZSTR_VAL(arg)[i]) != NULL) { + return true; + } + } + return false; +} + +/* See https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments and + * https://learn.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way */ +static void append_win_escaped_arg(smart_str *str, zend_string *arg, bool is_cmd_argument) { size_t num_bs = 0; + bool has_special_character = false; + if (is_cmd_argument) { + has_special_character = is_special_character_present(arg); + if (has_special_character) { + /* Escape double quote with ^ if executed by cmd.exe. */ + smart_str_appendc(str, '^'); + } + } smart_str_appendc(str, '"'); for (size_t i = 0; i < ZSTR_LEN(arg); ++i) { char c = ZSTR_VAL(arg)[i]; @@ -510,18 +531,71 @@ static void append_win_escaped_arg(smart_str *str, zend_string *arg) num_bs = num_bs * 2 + 1; } append_backslashes(str, num_bs); + if (has_special_character && strchr(special_chars, c) != NULL) { + /* Escape special chars with ^ if executed by cmd.exe. */ + smart_str_appendc(str, '^'); + } smart_str_appendc(str, c); num_bs = 0; } append_backslashes(str, num_bs * 2); + if (has_special_character) { + /* Escape double quote with ^ if executed by cmd.exe. */ + smart_str_appendc(str, '^'); + } smart_str_appendc(str, '"'); } +static inline int stricmp_end(const char* suffix, const char* str) { + size_t suffix_len = strlen(suffix); + size_t str_len = strlen(str); + + if (suffix_len > str_len) { + return -1; /* Suffix is longer than string, cannot match. */ + } + + /* Compare the end of the string with the suffix, ignoring case. */ + return _stricmp(str + (str_len - suffix_len), suffix); +} + +static bool is_executed_by_cmd(const char *prog_name) +{ + /* If program name is cmd.exe, then return true. */ + if (_stricmp("cmd.exe", prog_name) == 0 || _stricmp("cmd", prog_name) == 0 + || stricmp_end("\\cmd.exe", prog_name) == 0 || stricmp_end("\\cmd", prog_name) == 0) { + return true; + } + + /* Find the last occurrence of the directory separator (backslash or forward slash). */ + char *last_separator = strrchr(prog_name, '\\'); + char *last_separator_fwd = strrchr(prog_name, '/'); + if (last_separator_fwd && (!last_separator || last_separator < last_separator_fwd)) { + last_separator = last_separator_fwd; + } + + /* Find the last dot in the filename after the last directory separator. */ + char *extension = NULL; + if (last_separator != NULL) { + extension = strrchr(last_separator, '.'); + } else { + extension = strrchr(prog_name, '.'); + } + + if (extension == NULL || extension == prog_name) { + /* No file extension found, it is not batch file. */ + return false; + } + + /* Check if the file extension is ".bat" or ".cmd" which is always executed by cmd.exe. */ + return _stricmp(extension, ".bat") == 0 || _stricmp(extension, ".cmd") == 0; +} + static zend_string *create_win_command_from_args(HashTable *args) { smart_str str = {0}; zval *arg_zv; - bool is_prog_name = 1; + bool is_prog_name = true; + bool is_cmd_execution = false; int elem_num = 0; ZEND_HASH_FOREACH_VAL(args, arg_zv) { @@ -531,11 +605,13 @@ static zend_string *create_win_command_from_args(HashTable *args) return NULL; } - if (!is_prog_name) { + if (is_prog_name) { + is_cmd_execution = is_executed_by_cmd(ZSTR_VAL(arg_str)); + } else { smart_str_appendc(&str, ' '); } - append_win_escaped_arg(&str, arg_str); + append_win_escaped_arg(&str, arg_str, !is_prog_name && is_cmd_execution); is_prog_name = 0; zend_string_release(arg_str); @@ -646,7 +722,7 @@ static zend_string* get_command_from_array(HashTable *array, char ***argv, int n static descriptorspec_item* alloc_descriptor_array(HashTable *descriptorspec) { uint32_t ndescriptors = zend_hash_num_elements(descriptorspec); - return ecalloc(sizeof(descriptorspec_item), ndescriptors); + return ecalloc(ndescriptors, sizeof(descriptorspec_item)); } static zend_string* get_string_parameter(zval *array, int index, char *param_name) diff --git a/ext/standard/tests/file/file_put_contents_5gb.phpt b/ext/standard/tests/file/file_get_contents_file_put_contents_5gb.phpt similarity index 60% rename from ext/standard/tests/file/file_put_contents_5gb.phpt rename to ext/standard/tests/file/file_get_contents_file_put_contents_5gb.phpt index d552d86279d03..854996a6481e7 100644 --- a/ext/standard/tests/file/file_put_contents_5gb.phpt +++ b/ext/standard/tests/file/file_get_contents_file_put_contents_5gb.phpt @@ -1,5 +1,5 @@ --TEST-- -Test file_put_contents() function with 5GB string +Test file_put_contents() and file_get_contents() functions with 5GB string --SKIPIF-- --CLEAN-- --EXPECT-- File written successfully. +File read successfully. diff --git a/ext/standard/tests/file/rename_variation2-win32.phpt b/ext/standard/tests/file/rename_variation2-win32.phpt index b486fcc543d63..b23e1a1bbb048 100644 --- a/ext/standard/tests/file/rename_variation2-win32.phpt +++ b/ext/standard/tests/file/rename_variation2-win32.phpt @@ -11,35 +11,35 @@ if (substr(PHP_OS, 0, 3) != 'WIN') { require __DIR__.'/file.inc'; $file_path = __DIR__; -mkdir("$file_path/rename_variation2_dir"); +mkdir("$file_path/rename_variation2-win32_dir"); /* Renaming a file and directory to numeric name */ echo "\n*** Testing rename() by renaming a file and directory to numeric name ***\n"; -$fp = fopen($file_path."/rename_variation2.tmp", "w"); +$fp = fopen($file_path."/rename_variation2-win32.tmp", "w"); fclose($fp); // renaming existing file to numeric name -var_dump( rename($file_path."/rename_variation2.tmp", $file_path."/12345") ); +var_dump( rename($file_path."/rename_variation2-win32.tmp", $file_path."/12346") ); // ensure that rename worked fine -var_dump( file_exists($file_path."/rename_variation2.tmp" ) ); // expecting false -var_dump( file_exists($file_path."/12345" ) ); // expecting true +var_dump( file_exists($file_path."/rename_variation2-win32.tmp" ) ); // expecting false +var_dump( file_exists($file_path."/12346" ) ); // expecting true -unlink($file_path."/12345"); +unlink($file_path."/12346"); // renaming a directory to numeric name -var_dump( rename($file_path."/rename_variation2_dir/", $file_path."/12345") ); +var_dump( rename($file_path."/rename_variation2-win32_dir/", $file_path."/12346") ); // ensure that rename worked fine -var_dump( file_exists($file_path."/rename_variation2_dir" ) ); // expecting false -var_dump( file_exists($file_path."/12345" ) ); // expecting true +var_dump( file_exists($file_path."/rename_variation2-win32_dir" ) ); // expecting false +var_dump( file_exists($file_path."/12346" ) ); // expecting true echo "Done\n"; ?> --CLEAN-- --EXPECT-- *** Testing rename() by renaming a file and directory to numeric name *** diff --git a/ext/standard/tests/filters/gh13264.phpt b/ext/standard/tests/filters/gh13264.phpt new file mode 100644 index 0000000000000..6456a082a1e40 --- /dev/null +++ b/ext/standard/tests/filters/gh13264.phpt @@ -0,0 +1,49 @@ +--TEST-- +GH-81475: Memory leak during stream filter failure +--SKIPIF-- + +--FILE-- + 15]); + +// Read the filtered stream line by line. +while (($line = fgets($stream)) !== false) { + $error = error_get_last(); + if ($error !== null) { + // An error is thrown but fgets didn't return false + var_dump(error_get_last()); + var_dump($line); + } +} + +fclose($stream); +?> +--EXPECTF-- + +Notice: fgets(): zlib: data error in %s on line %d +array(4) { + ["type"]=> + int(8) + ["message"]=> + string(25) "fgets(): zlib: data error" + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) +} +string(7) "Hello 6" + diff --git a/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_1.phpt b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_1.phpt new file mode 100644 index 0000000000000..8d0939cdf1bc7 --- /dev/null +++ b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_1.phpt @@ -0,0 +1,29 @@ +--TEST-- +GHSA-54hq-v5wp-fqgv - proc_open does not correctly escape args for bat files +--SKIPIF-- + +--FILE-- + +--EXPECT-- +"¬epad.exe +--CLEAN-- + diff --git a/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_2.phpt b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_2.phpt new file mode 100644 index 0000000000000..a1e39d7ef9ba0 --- /dev/null +++ b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_2.phpt @@ -0,0 +1,29 @@ +--TEST-- +GHSA-54hq-v5wp-fqgv - proc_open does not correctly escape args for cmd files +--SKIPIF-- + +--FILE-- +^()!.exe"], $descriptorspec, $pipes); +proc_close($proc); + +?> +--EXPECT-- +"¬epad<>^()!.exe +--CLEAN-- + diff --git a/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_3.phpt b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_3.phpt new file mode 100644 index 0000000000000..69f12d7b358d2 --- /dev/null +++ b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_3.phpt @@ -0,0 +1,29 @@ +--TEST-- +GHSA-54hq-v5wp-fqgv - proc_open does not correctly escape args for cmd executing batch files +--SKIPIF-- + +--FILE-- + +--EXPECT-- +"¬epad.exe +--CLEAN-- + diff --git a/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt b/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt new file mode 100644 index 0000000000000..77fcb68089488 --- /dev/null +++ b/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt @@ -0,0 +1,63 @@ +--TEST-- +ghsa-wpj3-hf5j-x4v4 (__Host-/__Secure- cookie bypass due to partial CVE-2022-31629 fix) +--COOKIE-- +..Host-test=ignore_1; +._Host-test=ignore_2; +.[Host-test=ignore_3; +_.Host-test=ignore_4; +__Host-test=ignore_5; +_[Host-test=ignore_6; +[.Host-test=ignore_7; +[_Host-test=ignore_8; +[[Host-test=ignore_9; +..Host-test[]=ignore_10; +._Host-test[]=ignore_11; +.[Host-test[]=ignore_12; +_.Host-test[]=ignore_13; +__Host-test[]=legitimate_14; +_[Host-test[]=legitimate_15; +[.Host-test[]=ignore_16; +[_Host-test[]=ignore_17; +[[Host-test[]=ignore_18; +..Secure-test=ignore_1; +._Secure-test=ignore_2; +.[Secure-test=ignore_3; +_.Secure-test=ignore_4; +__Secure-test=ignore_5; +_[Secure-test=ignore_6; +[.Secure-test=ignore_7; +[_Secure-test=ignore_8; +[[Secure-test=ignore_9; +..Secure-test[]=ignore_10; +._Secure-test[]=ignore_11; +.[Secure-test[]=ignore_12; +_.Secure-test[]=ignore_13; +__Secure-test[]=legitimate_14; +_[Secure-test[]=legitimate_15; +[.Secure-test[]=ignore_16; +[_Secure-test[]=ignore_17; +[[Secure-test[]=ignore_18; +--FILE-- + +--EXPECT-- +array(3) { + ["__Host-test"]=> + array(1) { + [0]=> + string(13) "legitimate_14" + } + ["_"]=> + array(2) { + ["Host-test["]=> + string(13) "legitimate_15" + ["Secure-test["]=> + string(13) "legitimate_15" + } + ["__Secure-test"]=> + array(1) { + [0]=> + string(13) "legitimate_14" + } +} diff --git a/ext/standard/tests/password/password_bcrypt_errors.phpt b/ext/standard/tests/password/password_bcrypt_errors.phpt index 10c3483f5a80d..5d823cba0217d 100644 --- a/ext/standard/tests/password/password_bcrypt_errors.phpt +++ b/ext/standard/tests/password/password_bcrypt_errors.phpt @@ -14,7 +14,14 @@ try { } catch (ValueError $exception) { echo $exception->getMessage() . "\n"; } + +try { + var_dump(password_hash("null\0password", PASSWORD_BCRYPT)); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} ?> --EXPECT-- Invalid bcrypt cost parameter specified: 3 Invalid bcrypt cost parameter specified: 32 +Bcrypt password must not contain null character diff --git a/ext/standard/url_scanner_ex.re b/ext/standard/url_scanner_ex.re index 8e5b43467fc88..77b4d79793b65 100644 --- a/ext/standard/url_scanner_ex.re +++ b/ext/standard/url_scanner_ex.re @@ -138,9 +138,11 @@ static int php_ini_on_update_hosts(zend_ini_entry *entry, zend_string *new_value } keylen = q - key; if (keylen > 0) { - tmp_key = zend_string_init(key, keylen, 0); + /* Note: the hash table is persistently allocated, so the strings must be too! */ + tmp_key = zend_string_init(key, keylen, true); + GC_MAKE_PERSISTENT_LOCAL(tmp_key); zend_hash_add_empty_element(hosts, tmp_key); - zend_string_release_ex(tmp_key, 0); + zend_string_release_ex(tmp_key, true); } } efree(tmp); diff --git a/ext/standard/user_filters.c b/ext/standard/user_filters.c index dcbfc381d295f..8995471af4597 100644 --- a/ext/standard/user_filters.c +++ b/ext/standard/user_filters.c @@ -196,22 +196,7 @@ php_stream_filter_status_t userfilter_filter( } if (buckets_in->head) { - php_stream_bucket *bucket; - php_error_docref(NULL, E_WARNING, "Unprocessed filter buckets remaining on input brigade"); - while ((bucket = buckets_in->head)) { - /* Remove unconsumed buckets from the brigade */ - php_stream_bucket_unlink(bucket); - php_stream_bucket_delref(bucket); - } - } - if (ret != PSFS_PASS_ON) { - php_stream_bucket *bucket = buckets_out->head; - while (bucket != NULL) { - php_stream_bucket_unlink(bucket); - php_stream_bucket_delref(bucket); - bucket = buckets_out->head; - } } /* filter resources are cleaned up by the stream destructor, diff --git a/ext/zend_test/observer.c b/ext/zend_test/observer.c index de83d7beb18c5..af45f91a5da5b 100644 --- a/ext/zend_test/observer.c +++ b/ext/zend_test/observer.c @@ -67,8 +67,16 @@ static void observer_show_opcode(zend_execute_data *execute_data) php_printf("%*s\n", 2 * ZT_G(observer_nesting_depth), "", zend_get_opcode_name(EX(opline)->opcode)); } +static inline void assert_observer_opline(zend_execute_data *execute_data) { + ZEND_ASSERT(!ZEND_USER_CODE(EX(func)->type) || + (EX(opline) >= EX(func)->op_array.opcodes && EX(opline) < EX(func)->op_array.opcodes + EX(func)->op_array.last) || + (EX(opline) >= EG(exception_op) && EX(opline) < EG(exception_op) + 3)); +} + static void observer_begin(zend_execute_data *execute_data) { + assert_observer_opline(execute_data); + if (!ZT_G(observer_show_output)) { return; } @@ -112,6 +120,8 @@ static void get_retval_info(zval *retval, smart_str *buf) static void observer_end(zend_execute_data *execute_data, zval *retval) { + assert_observer_opline(execute_data); + if (!ZT_G(observer_show_output)) { return; } diff --git a/ext/zend_test/tests/gh9871.phpt b/ext/zend_test/tests/gh9871.phpt index d2915fff6f8c8..b40a20a2609ec 100644 --- a/ext/zend_test/tests/gh9871.phpt +++ b/ext/zend_test/tests/gh9871.phpt @@ -5,6 +5,7 @@ zend_test --INI-- opcache.enable_cli=1 zend_test.observer.enabled=1 +zend_test.observer.show_output=1 zend_test.observer.observe_all=1 zend_test.observer.show_return_value=1 --FILE-- diff --git a/ext/zend_test/tests/observer_backtrace_01.phpt b/ext/zend_test/tests/observer_backtrace_01.phpt index 7f021bf402515..d95ee7bdf4ca9 100644 --- a/ext/zend_test/tests/observer_backtrace_01.phpt +++ b/ext/zend_test/tests/observer_backtrace_01.phpt @@ -4,6 +4,7 @@ Observer: Show backtrace on init zend_test --INI-- zend_test.observer.enabled=1 +zend_test.observer.show_output=1 zend_test.observer.observe_all=1 zend_test.observer.show_init_backtrace=1 --FILE-- diff --git a/ext/zend_test/tests/observer_basic_01.phpt b/ext/zend_test/tests/observer_basic_01.phpt index b208ae2341e85..435a46c8407ec 100644 --- a/ext/zend_test/tests/observer_basic_01.phpt +++ b/ext/zend_test/tests/observer_basic_01.phpt @@ -4,6 +4,7 @@ Observer: Basic observability of userland functions zend_test --INI-- zend_test.observer.enabled=1 +zend_test.observer.show_output=1 zend_test.observer.observe_all=1 --FILE-- = sizeof("__Host-")-1 && strncmp(mangled_name, "__Host-", sizeof("__Host-")-1) == 0 && strncmp(pre_mangled_name, "__Host-", sizeof("__Host-")-1) != 0) { + return true; + } + + if (mangled_name_len >= sizeof("__Secure-")-1 && strncmp(mangled_name, "__Secure-", sizeof("__Secure-")-1) == 0 && strncmp(pre_mangled_name, "__Secure-", sizeof("__Secure-")-1) != 0) { + return true; + } + + return false; +} + PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *track_vars_array) { char *p = NULL; @@ -139,20 +154,6 @@ PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *trac } var_len = p - var; - /* Discard variable if mangling made it start with __Host-, where pre-mangling it did not start with __Host- */ - if (strncmp(var, "__Host-", sizeof("__Host-")-1) == 0 && strncmp(var_name, "__Host-", sizeof("__Host-")-1) != 0) { - zval_ptr_dtor_nogc(val); - free_alloca(var_orig, use_heap); - return; - } - - /* Discard variable if mangling made it start with __Secure-, where pre-mangling it did not start with __Secure- */ - if (strncmp(var, "__Secure-", sizeof("__Secure-")-1) == 0 && strncmp(var_name, "__Secure-", sizeof("__Secure-")-1) != 0) { - zval_ptr_dtor_nogc(val); - free_alloca(var_orig, use_heap); - return; - } - if (var_len==0) { /* empty variable name, or variable name with a space in it */ zval_ptr_dtor_nogc(val); free_alloca(var_orig, use_heap); @@ -256,6 +257,12 @@ PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *trac return; } } else { + if (php_is_forbidden_variable_name(index, index_len, var_name)) { + zval_ptr_dtor_nogc(val); + free_alloca(var_orig, use_heap); + return; + } + gpc_element_p = zend_symtable_str_find(symtable1, index, index_len); if (!gpc_element_p) { zval tmp; @@ -293,6 +300,12 @@ PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *trac zval_ptr_dtor_nogc(val); } } else { + if (php_is_forbidden_variable_name(index, index_len, var_name)) { + zval_ptr_dtor_nogc(val); + free_alloca(var_orig, use_heap); + return; + } + zend_ulong idx; /* diff --git a/main/php_version.h b/main/php_version.h index c5491beea546d..6a9708f9d0bd6 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 2 -#define PHP_RELEASE_VERSION 18 -#define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.2.18-dev" -#define PHP_VERSION_ID 80218 +#define PHP_RELEASE_VERSION 19 +#define PHP_EXTRA_VERSION "" +#define PHP_VERSION "8.2.19" +#define PHP_VERSION_ID 80219 diff --git a/main/streams/cast.c b/main/streams/cast.c index 3bad65fbac1f5..8d9f4a9d2d54b 100644 --- a/main/streams/cast.c +++ b/main/streams/cast.c @@ -104,6 +104,9 @@ static ssize_t stream_cookie_writer(void *cookie, const char *buffer, size_t siz # ifdef COOKIE_SEEKER_USES_OFF64_T static int stream_cookie_seeker(void *cookie, off64_t *position, int whence) +# else +static int stream_cookie_seeker(void *cookie, off_t *position, int whence) +# endif { *position = php_stream_seek((php_stream *)cookie, (zend_off_t)*position, whence); @@ -113,13 +116,6 @@ static int stream_cookie_seeker(void *cookie, off64_t *position, int whence) } return 0; } -# else -static int stream_cookie_seeker(void *cookie, zend_off_t position, int whence) -{ - - return php_stream_seek((php_stream *)cookie, position, whence); -} -# endif static int stream_cookie_closer(void *cookie) { diff --git a/main/streams/glob_wrapper.c b/main/streams/glob_wrapper.c index 813e0bacdfd3f..45147f3fe614a 100644 --- a/main/streams/glob_wrapper.c +++ b/main/streams/glob_wrapper.c @@ -225,7 +225,7 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha } } - pglob = ecalloc(sizeof(*pglob), 1); + pglob = ecalloc(1, sizeof(*pglob)); if (0 != (ret = glob(path, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) { #ifdef GLOB_NOMATCH diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index c77bd1e2415a8..c92b76d196da0 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -54,7 +54,7 @@ extern int php_get_gid_by_name(const char *name, gid_t *gid); #endif #if defined(PHP_WIN32) -# define PLAIN_WRAP_BUF_SIZE(st) (((st) > UINT_MAX) ? UINT_MAX : (unsigned int)(st)) +# define PLAIN_WRAP_BUF_SIZE(st) ((unsigned int)(st > INT_MAX ? INT_MAX : st)) #define fsync _commit #define fdatasync fsync #else @@ -354,7 +354,7 @@ static ssize_t php_stdiop_write(php_stream *stream, const char *buf, size_t coun if (data->fd >= 0) { #ifdef PHP_WIN32 - ssize_t bytes_written = _write(data->fd, buf, (unsigned int)(count > INT_MAX ? INT_MAX : count)); + ssize_t bytes_written = _write(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count)); #else ssize_t bytes_written = write(data->fd, buf, count); #endif diff --git a/main/streams/streams.c b/main/streams/streams.c index d45a9bfab85f8..33f8b7e7a80cd 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -632,6 +632,17 @@ PHPAPI zend_result _php_stream_fill_read_buffer(php_stream *stream, size_t size) /* some fatal error. Theoretically, the stream is borked, so all * further reads should fail. */ stream->eof = 1; + /* free all data left in brigades */ + while ((bucket = brig_inp->head)) { + /* Remove unconsumed buckets from the input brigade */ + php_stream_bucket_unlink(bucket); + php_stream_bucket_delref(bucket); + } + while ((bucket = brig_outp->head)) { + /* Remove unconsumed buckets from the output brigade */ + php_stream_bucket_unlink(bucket); + php_stream_bucket_delref(bucket); + } efree(chunk_buf); return FAILURE; } diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c index ef9b35a9994aa..e1aec90ff3e83 100644 --- a/sapi/fpm/fpm/fpm_conf.c +++ b/sapi/fpm/fpm/fpm_conf.c @@ -213,8 +213,22 @@ static int fpm_conf_expand_pool_name(char **value) { static char *fpm_conf_set_boolean(zval *value, void **config, intptr_t offset) /* {{{ */ { zend_string *val = Z_STR_P(value); - bool value_y = zend_string_equals_literal(val, "1"); - bool value_n = ZSTR_LEN(val) == 0; /* Empty string is the only valid false value */ + /* we need to check all allowed values to correctly set value from the environment variable */ + bool value_y = ( + zend_string_equals_literal(val, "1") || + zend_string_equals_literal(val, "yes") || + zend_string_equals_literal(val, "true") || + zend_string_equals_literal(val, "on") + ); + bool value_n = ( + value_y || ZSTR_LEN(val) == 0 || + zend_string_equals_literal(val, "0") || + zend_string_equals_literal(val, "no") || + zend_string_equals_literal(val, "none") || + zend_string_equals_literal(val, "false") || + zend_string_equals_literal(val, "off") + ); + if (!value_y && !value_n) { return "invalid boolean value"; diff --git a/sapi/fpm/tests/gh13563-conf-bool-env.phpt b/sapi/fpm/tests/gh13563-conf-bool-env.phpt new file mode 100644 index 0000000000000..15dce0ecf9b5a --- /dev/null +++ b/sapi/fpm/tests/gh13563-conf-bool-env.phpt @@ -0,0 +1,75 @@ +--TEST-- +FPM: GH-13563 - conf boolean environment variables values +--SKIPIF-- + +--FILE-- + \$val) { + if (str_starts_with(\$name, 'FPM_TEST')) { + printf("%s: %s\n", \$name, \$val); + } +} +file_put_contents('php://stderr', str_repeat('a', 20) . "\n"); +EOT; + +$tester = new FPM\Tester($cfg, $code); +$tester->start(envVars: [ + 'FPM_TEST_LOG_BUF' => 'on', + 'FPM_TEST_DAEMONIZE' => 'false', + 'FPM_TEST_PROC_DUMP' => 'no', + 'FPM_TEST_CATCH_WRK_OUT' => 'yes', + 'FPM_TEST_DECOR_WRK_OUT' => 'true', + 'FPM_TEST_CLEAR_ENV' => 'none', + 'FPM_TEST_REQ_TERM_TRACK_FIN' => '0', +]); +$tester->expectLogStartNotices(); +$tester->request()->expectBody([ + 'FPM_TEST_LOG_BUF: on', + 'FPM_TEST_DAEMONIZE: false', + 'FPM_TEST_PROC_DUMP: no', + 'FPM_TEST_CATCH_WRK_OUT: yes', + 'FPM_TEST_DECOR_WRK_OUT: true', + 'FPM_TEST_CLEAR_ENV: none', + 'FPM_TEST_REQ_TERM_TRACK_FIN: 0', +]); +$tester->terminate(); +$tester->expectLogMessage('a', 1024, 20, true); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/tester.inc b/sapi/fpm/tests/tester.inc index 66cbad175298d..ed0988f883ac1 100644 --- a/sapi/fpm/tests/tester.inc +++ b/sapi/fpm/tests/tester.inc @@ -417,11 +417,12 @@ class Tester /** * Start PHP-FPM master process * - * @param array $extraArgs Command extra arguments. - * @param bool $forceStderr Whether to output to stderr so error log is used. - * @param bool $daemonize Whether to start FPM daemonized - * @param array $extensions List of extension to add if shared build used. - * @param array $iniEntries List of ini entries to use. + * @param array $extraArgs Command extra arguments. + * @param bool $forceStderr Whether to output to stderr so error log is used. + * @param bool $daemonize Whether to start FPM daemonized + * @param array $extensions List of extension to add if shared build used. + * @param array $iniEntries List of ini entries to use. + * @param array|null $envVars List of env variable to execute FPM with or null to use the current ones. * * @return bool * @throws \Exception @@ -432,6 +433,7 @@ class Tester bool $daemonize = false, array $extensions = [], array $iniEntries = [], + ?array $envVars = null, ) { $configFile = $this->createConfig(); $desc = $this->outDesc ? [] : [1 => array('pipe', 'w'), 2 => array('redirect', 1)]; @@ -465,7 +467,7 @@ class Tester $cmd = array_merge($cmd, $extraArgs); $this->trace('Starting FPM using command:', $cmd, true); - $this->masterProcess = proc_open($cmd, $desc, $pipes); + $this->masterProcess = proc_open($cmd, $desc, $pipes, null, $envVars); register_shutdown_function( function ($masterProcess) use ($configFile) { @unlink($configFile); diff --git a/sapi/fuzzer/README.md b/sapi/fuzzer/README.md index ee2d0ee4e0262..b4bb2bbe4573f 100644 --- a/sapi/fuzzer/README.md +++ b/sapi/fuzzer/README.md @@ -26,7 +26,7 @@ When running `make` it creates these binaries in `sapi/fuzzer/`: * `php-fuzz-parser`: Fuzzing language parser and compiler * `php-fuzz-unserialize`: Fuzzing unserialize() function * `php-fuzz-unserializehash`: Fuzzing unserialize() for HashContext objects -* `php-fuzz-json`: Fuzzing JSON parser (requires --enable-json) +* `php-fuzz-json`: Fuzzing JSON parser * `php-fuzz-exif`: Fuzzing `exif_read_data()` function (requires --enable-exif) * `php-fuzz-mbstring`: Fuzzing `mb_convert_encoding()` (requires `--enable-mbstring`) * `php-fuzz-mbregex`: Fuzzing `mb_ereg[i]()` (requires --enable-mbstring) diff --git a/sapi/phpdbg/phpdbg_frame.c b/sapi/phpdbg/phpdbg_frame.c index 644668d8d14e5..3652d2b2bbaf2 100644 --- a/sapi/phpdbg/phpdbg_frame.c +++ b/sapi/phpdbg/phpdbg_frame.c @@ -274,7 +274,8 @@ void phpdbg_dump_backtrace(size_t num) /* {{{ */ Z_STR(startfile) = zend_string_init(startfilename, strlen(startfilename), 0); zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position); - tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position); + + zval *function_name = NULL; while ((tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position))) { if (file) { /* userland */ phpdbg_out("frame #%d: ", i); @@ -289,10 +290,18 @@ void phpdbg_dump_backtrace(size_t num) /* {{{ */ file = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("file")); line = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("line")); + function_name = zend_hash_find(Z_ARRVAL_P(tmp), ZSTR_KNOWN(ZEND_STR_FUNCTION)); + zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position); } - phpdbg_writeln("frame #%d: {main} at %s:"ZEND_LONG_FMT, i, Z_STRVAL_P(file), Z_LVAL_P(line)); + /* This is possible for fibers' start closure for example, which have a frame that doesn't contain the info + * of which location stated the fiber if that stack frame is already torn down. same behaviour with debug_backtrace(). */ + if (file == NULL) { + phpdbg_writeln(" => %s (internal function)", Z_STRVAL_P(function_name)); + } else { + phpdbg_writeln("frame #%d: {main} at %s:"ZEND_LONG_FMT, i, Z_STRVAL_P(file), Z_LVAL_P(line)); + } zval_ptr_dtor_nogc(&zbacktrace); zend_string_release(Z_STR(startfile)); diff --git a/sapi/phpdbg/tests/gh13827.phpt b/sapi/phpdbg/tests/gh13827.phpt new file mode 100644 index 0000000000000..3d7017bf309f5 --- /dev/null +++ b/sapi/phpdbg/tests/gh13827.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-13827 (Null pointer access of type 'zval' in phpdbg_frame) +--FILE-- +start(); + +$fiber = null; +gc_collect_cycles(); + +?> +--PHPDBG-- +r +t +q +--EXPECTF-- +[Successful compilation of %s] +prompt> [Uncaught GracefulExit in on line 0: ] +>00006: Fiber::suspend(); + 00007: }); + 00008: +prompt> frame #0: {closure}() at %s:6 + => {closure} (internal function) +prompt> diff --git a/sapi/phpdbg/tests/gh13931.phpt b/sapi/phpdbg/tests/gh13931.phpt new file mode 100644 index 0000000000000..25520435feb9b --- /dev/null +++ b/sapi/phpdbg/tests/gh13931.phpt @@ -0,0 +1,21 @@ +--TEST-- +Applying zero offset to null pointer in Zend/zend_opcode.c +--FILE-- + +--PHPDBG-- +ev 1 + 3 +ev 2 ** 3 +q +--EXPECTF-- +Fatal error: 'break' not in the 'loop' or 'switch' context in %s on line %d +prompt> 4 +prompt> 8 +prompt> diff --git a/sapi/phpdbg/tests/print_001.phpt b/sapi/phpdbg/tests/print_001.phpt index c25c5178fef4c..f192cb2ae9fcc 100644 --- a/sapi/phpdbg/tests/print_001.phpt +++ b/sapi/phpdbg/tests/print_001.phpt @@ -13,7 +13,7 @@ q prompt> [User Function foo (8 ops)] foo: - ; (lines=8, args=1, vars=1, tmps=2) + ; (lines=8, args=1, vars=1, tmps=%d) ; %s:14-16 L0014 0000 CV0($baz) = RECV 1 L0015 0001 INIT_FCALL %d %d string("var_dump") @@ -26,7 +26,7 @@ L0016 0007 RETURN null prompt> [User Class: Foo\Bar (2 methods)] Foo\Bar::Foo: - ; (lines=5, args=1, vars=1, tmps=1) + ; (lines=5, args=1, vars=1, tmps=%d) ; %s:5-7 L0005 0000 CV0($bar) = RECV 1 L0006 0001 INIT_NS_FCALL_BY_NAME 1 string("Foo\var_dump") @@ -35,14 +35,14 @@ L0006 0003 DO_FCALL L0007 0004 RETURN null Foo\Bar::baz: - ; (lines=1, args=0, vars=0, tmps=0) + ; (lines=1, args=0, vars=0, tmps=%d) ; %s:9-9 L0009 0000 RETURN null prompt> [Not Executing!] prompt> [Context %s (9 ops)] $_main: - ; (lines=9, args=0, vars=0, tmps=4) + ; (lines=9, args=0, vars=0, tmps=%d) ; %s:1-21 L0018 0000 V0 = NEW 0 string("Foo\Bar") L0018 0001 DO_FCALL diff --git a/sapi/phpdbg/tests/print_002.phpt b/sapi/phpdbg/tests/print_002.phpt index 2358b025d1741..3b46fe0c13c72 100644 --- a/sapi/phpdbg/tests/print_002.phpt +++ b/sapi/phpdbg/tests/print_002.phpt @@ -19,7 +19,7 @@ prompt> string(4) "test" prompt> [Stack in foo() (8 ops)] foo: - ; (lines=8, args=1, vars=1, tmps=2) + ; (lines=8, args=1, vars=1, tmps=%d) ; %s:14-16 L0014 0000 CV0($baz) = RECV 1 L0015 0001 INIT_FCALL %d %d string("var_dump") diff --git a/scripts/dev/makedist b/scripts/dev/makedist index 8e53f1d73a803..ffdf536907651 100755 --- a/scripts/dev/makedist +++ b/scripts/dev/makedist @@ -167,8 +167,9 @@ else fi # Reset the modification and access times of all files to be packaged. -echo "makedist: Resetting the modification and access times of package files." -touch -c NEWS +commitDate="$(git log -1 --format=%cI $treeish)" +echo "makedist: Resetting the modification and access times of package files to $commitDate" +touch -c -d"$commitDate" NEWS find . -exec touch -r NEWS -c {} \; cd ..