diff --git a/.gitignore b/.gitignore index 49acc9f2e1788..449963153f36b 100644 --- a/.gitignore +++ b/.gitignore @@ -177,6 +177,9 @@ php /ext/*/configure.ac /ext/*/run-tests.php +# Generated by ./configure if libc might be musl +/ext/gettext/tests/locale/en_US + # ------------------------------------------------------------------------------ # Generated by Windows build system # ------------------------------------------------------------------------------ diff --git a/NEWS b/NEWS index b31724b1b0338..6c8f280205642 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,116 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.3.15 +16 Jan 2025, PHP 8.3.16 + +- Core: + . Fixed bug GH-17106 (ZEND_MATCH_ERROR misoptimization). (ilutov) + . Fixed bug GH-17162 (zend_array_try_init() with dtor can cause engine UAF). + (nielsdos) + . Fixed bug GH-17101 (AST->string does not reproduce constructor property + promotion correctly). (nielsdos) + . Fixed bug GH-17211 (observer segfault on function loaded with dl()). + (Arnaud) + . Fixed bug GH-17216 (Trampoline crash on error). (nielsdos) + +- Date: + . Fixed bug GH-14709 DatePeriod::__construct() overflow on recurrences. + (David Carlier) + +- DBA: + . Skip test if inifile is disabled. (orlitzky) + +- DOM: + . Fixed bug GH-17224 (UAF in importNode). (nielsdos) + +- Embed: + . Make build command for program using embed portable. (dunglas) + +- FFI: + . Fixed bug #79075 (FFI header parser chokes on comments). (nielsdos) + . Fix memory leak on ZEND_FFI_TYPE_CHAR conversion failure. (nielsdos) + . Fixed bug GH-16013 and bug #80857 (Big endian issues). (Dmitry, nielsdos) + +- Filter: + . Fixed bug GH-16944 (Fix filtering special IPv4 and IPv6 ranges, by using + information from RFC 6890). (Derick) + +- FPM: + . Fixed bug GH-13437 (FPM: ERROR: scoreboard: failed to lock (already + locked)). (Jakub Zelenka) + . Fixed bug GH-17112 (Macro redefinitions). (cmb, nielsdos) + . Fixed bug GH-17208 (bug64539-status-json-encoding.phpt fail on 32-bits). + (nielsdos) + +- GD: + . Fixed bug GH-16255 (Unexpected nan value in ext/gd/libgd/gd_filter.c). + (nielsdos, cmb) + . Ported fix for libgd bug 276 (Sometimes pixels are missing when storing + images as BMPs). (cmb) + +- Gettext: + . Fixed bug GH-17202 (Segmentation fault ext/gettext/gettext.c + bindtextdomain()). (Michael Orlitzky) + +- Iconv: + . Fixed bug GH-17047 (UAF on iconv filter failure). (nielsdos) + +- LDAP: + . Fixed bug GH-17280 (ldap_search() fails when $attributes array has holes). + (nielsdos) + +- LibXML: + . Fixed bug GH-17223 (Memory leak in libxml encoding handling). (nielsdos) + +- MBString: + . Fixed bug GH-17112 (Macro redefinitions). (nielsdos, cmb) + +- Opcache: + . opcache_get_configuration() properly reports jit_prof_threshold. (cmb) + . Fixed bug GH-17246 (GC during SCCP causes segfault). (Dmitry) + +- PCNTL: + . Fix memory leak in cleanup code of pcntl_exec() when a non stringable + value is encountered past the first entry. (Girgias) + +- PgSql: + . Fixed bug GH-17158 (pg_fetch_result Shows Incorrect ArgumentCountError + Message when Called With 1 Argument). (nielsdos) + . Fixed further ArgumentCountError for calls with flexible + number of arguments. (David Carlier) + +- Phar: + . Fixed bug GH-17137 (Segmentation fault ext/phar/phar.c). (nielsdos) + +- SimpleXML: + . Fixed bug GH-17040 (SimpleXML's unset can break DOM objects). (nielsdos) + . Fixed bug GH-17153 (SimpleXML crash when using autovivification on + document). (nielsdos) + +- Sockets: + . Fixed bug GH-16276 (socket_strerror overflow handling with INT_MIN). + (David Carlier / cmb) + . Fixed overflow on SO_LINGER values setting, strengthening values check + on SO_SNDTIMEO/SO_RCVTIMEO for socket_set_option(). + (David Carlier) + +- SPL: + . Fixed bug GH-17225 (NULL deref in spl_directory.c). (nielsdos) + +- Streams: + . Fixed bug GH-17037 (UAF in user filter when adding existing filter name due + to incorrect error handling). (nielsdos) + . Fixed bug GH-16810 (overflow on fopen HTTP wrapper timeout value). + (David Carlier) + . Fixed bug GH-17067 (glob:// wrapper doesn't cater to CWD for ZTS builds). + (cmb) + +- Windows: + . Hardened proc_open() against cmd.exe hijacking. (cmb) + +- XML: + . Fixed bug GH-1718 (unreachable program point in zend_hash). (nielsdos) + +19 Dec 2024, PHP 8.3.15 - Calendar: . Fixed jdtogregorian overflow. (David Carlier) diff --git a/Zend/Optimizer/zend_optimizer.c b/Zend/Optimizer/zend_optimizer.c index d8ff9e5f0b8f3..857968e621b38 100644 --- a/Zend/Optimizer/zend_optimizer.c +++ b/Zend/Optimizer/zend_optimizer.c @@ -640,6 +640,7 @@ bool zend_optimizer_replace_by_const(zend_op_array *op_array, case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: case ZEND_MATCH: + case ZEND_MATCH_ERROR: case ZEND_JMP_NULL: { zend_op *end = op_array->opcodes + op_array->last; while (opline < end) { @@ -652,6 +653,7 @@ bool zend_optimizer_replace_by_const(zend_op_array *op_array, && opline->opcode != ZEND_SWITCH_LONG && opline->opcode != ZEND_SWITCH_STRING && opline->opcode != ZEND_MATCH + && opline->opcode != ZEND_MATCH_ERROR && opline->opcode != ZEND_JMP_NULL && (opline->opcode != ZEND_FREE || opline->extended_value != ZEND_FREE_ON_RETURN); diff --git a/Zend/tests/gh17162.phpt b/Zend/tests/gh17162.phpt new file mode 100644 index 0000000000000..bdf6ddbb36ba7 --- /dev/null +++ b/Zend/tests/gh17162.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-17162 (zend_array_try_init() with dtor can cause engine UAF) +--FILE-- +value = null; + } +} +$box = [new Test]; +// Using getimagesize() for the test because it's always available, +// but any function that uses zend_try_array_init() would work. +try { + getimagesize("dummy", $box); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Attempt to assign property "value" on null diff --git a/Zend/tests/named_params/gh17216.phpt b/Zend/tests/named_params/gh17216.phpt new file mode 100644 index 0000000000000..4cb4df0ec431e --- /dev/null +++ b/Zend/tests/named_params/gh17216.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-17216 (Trampoline crash on error) +--FILE-- + "b", 1]; +try { + forward_static_call_array($callback, $array); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +echo "Done\n"; +?> +--EXPECT-- +Cannot use positional argument after named argument +Done diff --git a/Zend/zend.h b/Zend/zend.h index daf064f8c4e02..466d8280a013b 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.3.15-dev" +#define ZEND_VERSION "4.3.16" #define ZEND_ENGINE_3 diff --git a/Zend/zend_API.c b/Zend/zend_API.c index e93c4a93b7d17..13c640a64dd51 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2817,7 +2817,14 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend } internal_function->type = ZEND_INTERNAL_FUNCTION; internal_function->module = EG(current_module); - internal_function->T = 0; + if (EG(active) && ZEND_OBSERVER_ENABLED) { + /* Add an observer temporary to store previous observed frames. This is + * normally handled by zend_observer_post_startup(), except for + * functions registered at runtime (EG(active)). */ + internal_function->T = 1; + } else { + internal_function->T = 0; + } memset(internal_function->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*)); while (ptr->fname) { diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 1114eeeec14ef..59d489f7aeea2 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -1478,7 +1478,10 @@ static zend_always_inline zval *zend_try_array_init_size(zval *zv, uint32_t size } zv = &ref->val; } - zval_ptr_dtor(zv); + zval garbage; + ZVAL_COPY_VALUE(&garbage, zv); + ZVAL_NULL(zv); + zval_ptr_dtor(&garbage); ZVAL_ARR(zv, arr); return zv; } diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 525d9dfe9a742..bf602449e5e4e 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -2443,6 +2443,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio if (ast->child[3]) { zend_ast_export_attributes(str, ast->child[3], indent, 0); } + zend_ast_export_visibility(str, ast->attr); if (ast->child[0]) { zend_ast_export_type(str, ast->child[0], indent); smart_str_appendc(str, ' '); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index e9b6009af05ae..fe37b024934df 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -842,7 +842,11 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_ ZEND_CALL_NUM_ARGS(call) = i; cleanup_args: zend_vm_stack_free_args(call); + if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zend_free_extra_named_params(call->extra_named_params); + } zend_vm_stack_free_call_frame(call); + zend_release_fcall_info_cache(fci_cache); return SUCCESS; } } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 93195a1be4c54..55bf81376d99d 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -877,6 +877,7 @@ static bool keeps_op1_alive(zend_op *opline) { || opline->opcode == ZEND_SWITCH_LONG || opline->opcode == ZEND_SWITCH_STRING || opline->opcode == ZEND_MATCH + || opline->opcode == ZEND_MATCH_ERROR || opline->opcode == ZEND_FETCH_LIST_R || opline->opcode == ZEND_FETCH_LIST_W || opline->opcode == ZEND_COPY_TMP) { diff --git a/configure.ac b/configure.ac index d15c390e09355..5eba642a5b238 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.3.15-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.3.16],[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/date/php_date.c b/ext/date/php_date.c index 7cff8e13e23d5..436af32f93536 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -4903,9 +4903,11 @@ static bool date_period_init_iso8601_string(php_period_obj *dpobj, zend_class_en static bool date_period_init_finish(php_period_obj *dpobj, zend_long options, zend_long recurrences) { - if (dpobj->end == NULL && recurrences < 1) { + const zend_long max_recurrences = (INT_MAX - 8); + + if (dpobj->end == NULL && (recurrences < 1 || recurrences > max_recurrences)) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): Recurrence count must be greater than 0", ZSTR_VAL(func)); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): Recurrence count must be greater or equal to 1 and lower than " ZEND_LONG_FMT, ZSTR_VAL(func), max_recurrences + 1); zend_string_release(func); return false; } @@ -4914,8 +4916,17 @@ static bool date_period_init_finish(php_period_obj *dpobj, zend_long options, ze dpobj->include_start_date = !(options & PHP_DATE_PERIOD_EXCLUDE_START_DATE); dpobj->include_end_date = options & PHP_DATE_PERIOD_INCLUDE_END_DATE; - /* recurrrences */ - dpobj->recurrences = recurrences + dpobj->include_start_date + dpobj->include_end_date; + /* recurrences */ + recurrences += dpobj->include_start_date + dpobj->include_end_date; + + if (UNEXPECTED(recurrences > max_recurrences)) { + zend_string *func = get_active_function_or_method_name(); + zend_throw_exception_ex(date_ce_date_malformed_string_exception, 0, "%s(): Recurrence count must be greater or equal to 1 and lower than " ZEND_LONG_FMT " (including options)", ZSTR_VAL(func), max_recurrences + 1); + zend_string_release(func); + return false; + } + + dpobj->recurrences = (int)recurrences; dpobj->initialized = 1; diff --git a/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt b/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt index f2e121db389a3..31c6868d67fb2 100644 --- a/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt +++ b/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt @@ -15,6 +15,6 @@ try { } ?> ---EXPECT-- -DatePeriod::__construct(): Recurrence count must be greater than 0 -DatePeriod::__construct(): Recurrence count must be greater than 0 +--EXPECTF-- +DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d +DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d diff --git a/ext/date/tests/date_period_bad_iso_format.phpt b/ext/date/tests/date_period_bad_iso_format.phpt index dde177e739871..92b82f9962d19 100644 --- a/ext/date/tests/date_period_bad_iso_format.phpt +++ b/ext/date/tests/date_period_bad_iso_format.phpt @@ -40,10 +40,10 @@ try { } ?> ---EXPECT-- +--EXPECTF-- DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain a start date, "R4" given DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): ISO interval must contain a start date, "R4" given DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given -DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater than 0 -DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): Recurrence count must be greater than 0 +DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d +DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): Recurrence count must be greater or equal to 1 and lower than %d diff --git a/ext/date/tests/gh14709.phpt b/ext/date/tests/gh14709.phpt new file mode 100644 index 0000000000000..4669d74d4f275 --- /dev/null +++ b/ext/date/tests/gh14709.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug GH-14709 overflow on reccurences parameter +--FILE-- +getMessage(), PHP_EOL; +} + +try { + new DatePeriod($start, $interval, 2147483639, DatePeriod::EXCLUDE_START_DATE | DatePeriod::INCLUDE_END_DATE); +} catch (Exception $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +?> +--EXPECTF-- +DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d +DateMalformedStringException: DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d (including options) diff --git a/ext/dba/tests/gh16390.phpt b/ext/dba/tests/gh16390.phpt index 0b66e742a40ab..1c9d1f3a52e06 100644 --- a/ext/dba/tests/gh16390.phpt +++ b/ext/dba/tests/gh16390.phpt @@ -2,6 +2,11 @@ GH-16390 (dba_open() can segfault for "pathless" streams) --EXTENSIONS-- dba +--SKIPIF-- + --FILE-- doc, root, nodep->ns->href); + nsptr = xmlSearchNsByHref (docp, root, nodep->ns->href); if (nsptr == NULL || nsptr->prefix == NULL) { int errorcode; nsptr = dom_get_ns(root, (char *) nodep->ns->href, &errorcode, (char *) nodep->ns->prefix); /* If there is no root, the namespace cannot be attached to it, so we have to attach it to the old list. */ if (nsptr != NULL && root == NULL) { - php_libxml_set_old_ns(nodep->doc, nsptr); + php_libxml_set_old_ns(docp, nsptr); } } retnodep->ns = nsptr; diff --git a/ext/dom/tests/gh17223.phpt b/ext/dom/tests/gh17223.phpt new file mode 100644 index 0000000000000..6a0f274c2f64d --- /dev/null +++ b/ext/dom/tests/gh17223.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-17223 (Memory leak in libxml encoding handling) +--EXTENSIONS-- +dom +--FILE-- +save("%00"); +echo "Done\n"; +?> +--EXPECT-- +Done diff --git a/ext/dom/tests/gh17224.phpt b/ext/dom/tests/gh17224.phpt new file mode 100644 index 0000000000000..9430096a27416 --- /dev/null +++ b/ext/dom/tests/gh17224.phpt @@ -0,0 +1,67 @@ +--TEST-- +GH-17224 (UAF in importNode) +--EXTENSIONS-- +dom +--CREDITS-- +YuanchengJiang +--FILE-- +loadXML(''); +$attr = $fromdom->firstChild->attributes->item(0); +$att = $aDOM->importNode($attr); +$doc = new DOMDocument; +$fromdom->load(__DIR__."/book.xml"); +unset($attr); +var_dump($att); +?> +--EXPECTF-- +object(DOMAttr)#%d (%d) { + ["specified"]=> + bool(true) + ["schemaTypeInfo"]=> + NULL + ["name"]=> + string(4) "attr" + ["value"]=> + string(10) "namespaced" + ["ownerElement"]=> + NULL + ["nodeName"]=> + string(7) "ai:attr" + ["nodeValue"]=> + string(10) "namespaced" + ["nodeType"]=> + int(2) + ["parentNode"]=> + NULL + ["parentElement"]=> + NULL + ["childNodes"]=> + string(22) "(object value omitted)" + ["firstChild"]=> + string(22) "(object value omitted)" + ["lastChild"]=> + string(22) "(object value omitted)" + ["previousSibling"]=> + NULL + ["nextSibling"]=> + NULL + ["attributes"]=> + NULL + ["isConnected"]=> + bool(false) + ["ownerDocument"]=> + string(22) "(object value omitted)" + ["namespaceURI"]=> + string(15) "http://test.org/" + ["prefix"]=> + string(2) "ai" + ["localName"]=> + string(4) "attr" + ["baseURI"]=> + NULL + ["textContent"]=> + string(10) "namespaced" +} diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 06a79d250a633..f9ad84a192649 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -807,6 +807,7 @@ static zend_always_inline zend_result zend_ffi_zval_to_cdata(void *ptr, zend_ffi if (ZSTR_LEN(str) == 1) { *(char*)ptr = ZSTR_VAL(str)[0]; } else { + zend_tmp_string_release(tmp_str); zend_ffi_assign_incompatible(value, type); return FAILURE; } @@ -984,6 +985,27 @@ static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, v ret_type = ZEND_FFI_TYPE(callback_data->type->func.ret_type); if (ret_type->kind != ZEND_FFI_TYPE_VOID) { zend_ffi_zval_to_cdata(ret, ret_type, &retval); + +#ifdef WORDS_BIGENDIAN + if (ret_type->size < sizeof(ffi_arg) + && ret_type->kind >= ZEND_FFI_TYPE_UINT8 + && ret_type->kind < ZEND_FFI_TYPE_POINTER) { + /* We need to widen the value (zero extend) */ + switch (ret_type->size) { + case 1: + *(ffi_arg*)ret = *(uint8_t*)ret; + break; + case 2: + *(ffi_arg*)ret = *(uint16_t*)ret; + break; + case 4: + *(ffi_arg*)ret = *(uint32_t*)ret; + break; + default: + break; + } + } +#endif } zval_ptr_dtor(&retval); @@ -2854,7 +2876,31 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */ } if (ZEND_FFI_TYPE(type->func.ret_type)->kind != ZEND_FFI_TYPE_VOID) { - zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1, 0); + zend_ffi_type *func_ret_type = ZEND_FFI_TYPE(type->func.ret_type); + +#ifdef WORDS_BIGENDIAN + if (func_ret_type->size < sizeof(ffi_arg) + && func_ret_type->kind >= ZEND_FFI_TYPE_UINT8 + && func_ret_type->kind < ZEND_FFI_TYPE_POINTER) { + + /* We need to narrow the value (truncate) */ + switch (func_ret_type->size) { + case 1: + *(uint8_t*)ret = *(ffi_arg*)ret; + break; + case 2: + *(uint16_t*)ret = *(ffi_arg*)ret; + break; + case 4: + *(uint32_t*)ret = *(ffi_arg*)ret; + break; + default: + break; + } + } +#endif + + zend_ffi_cdata_to_zval(NULL, ret, func_ret_type, BP_VAR_R, return_value, 0, 1, 0); } else { ZVAL_NULL(return_value); } @@ -4958,85 +5004,85 @@ ZEND_METHOD(FFI_CType, getFuncParameterType) /* {{{ */ } /* }}} */ +static char *zend_ffi_skip_ws_and_comments(char *p, bool allow_standalone_newline) +{ + while (true) { + if (*p == ' ' || *p == '\t') { + p++; + } else if (allow_standalone_newline && (*p == '\r' || *p == '\n' || *p == '\f' || *p == '\v')) { + p++; + } else if (allow_standalone_newline && *p == '/' && p[1] == '/') { + p += 2; + while (*p && *p != '\r' && *p != '\n') { + p++; + } + } else if (*p == '/' && p[1] == '*') { + p += 2; + while (*p && (*p != '*' || p[1] != '/')) { + p++; + } + if (*p == '*') { + p++; + if (*p == '/') { + p++; + } + } + } else { + break; + } + } + + return p; +} + static char *zend_ffi_parse_directives(const char *filename, char *code_pos, char **scope_name, char **lib, bool preload) /* {{{ */ { char *p; + code_pos = zend_ffi_skip_ws_and_comments(code_pos, true); + *scope_name = NULL; *lib = NULL; while (*code_pos == '#') { - if (strncmp(code_pos, "#define FFI_SCOPE", sizeof("#define FFI_SCOPE") - 1) == 0 - && (code_pos[sizeof("#define FFI_SCOPE") - 1] == ' ' - || code_pos[sizeof("#define FFI_SCOPE") - 1] == '\t')) { - p = code_pos + sizeof("#define FFI_SCOPE"); - while (*p == ' ' || *p == '\t') { - p++; - } - if (*p != '"') { - if (preload) { - zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_SCOPE define", filename); - } else { - zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_SCOPE define", filename); - } - return NULL; - } - p++; - if (*scope_name) { - if (preload) { - zend_error(E_WARNING, "FFI: failed pre-loading '%s', FFI_SCOPE defined twice", filename); - } else { - zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', FFI_SCOPE defined twice", filename); - } - return NULL; - } - *scope_name = p; - while (1) { - if (*p == '\"') { - *p = 0; + if (strncmp(code_pos, ZEND_STRL("#define")) == 0) { + p = zend_ffi_skip_ws_and_comments(code_pos + sizeof("#define") - 1, false); + + char **target = NULL; + const char *target_name = NULL; + if (strncmp(p, ZEND_STRL("FFI_SCOPE")) == 0) { + p = zend_ffi_skip_ws_and_comments(p + sizeof("FFI_SCOPE") - 1, false); + target = scope_name; + target_name = "FFI_SCOPE"; + } else if (strncmp(p, ZEND_STRL("FFI_LIB")) == 0) { + p = zend_ffi_skip_ws_and_comments(p + sizeof("FFI_LIB") - 1, false); + target = lib; + target_name = "FFI_LIB"; + } else { + while (*p && *p != '\n' && *p != '\r') { p++; - break; - } else if (*p <= ' ') { - if (preload) { - zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_SCOPE define", filename); - } else { - zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_SCOPE define", filename); - } - return NULL; } - p++; - } - while (*p == ' ' || *p == '\t') { - p++; - } - while (*p == '\r' || *p == '\n') { - p++; - } - code_pos = p; - } else if (strncmp(code_pos, "#define FFI_LIB", sizeof("#define FFI_LIB") - 1) == 0 - && (code_pos[sizeof("#define FFI_LIB") - 1] == ' ' - || code_pos[sizeof("#define FFI_LIB") - 1] == '\t')) { - p = code_pos + sizeof("#define FFI_LIB"); - while (*p == ' ' || *p == '\t') { - p++; + code_pos = zend_ffi_skip_ws_and_comments(p, true); + continue; } + if (*p != '"') { if (preload) { - zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_LIB define", filename); + zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad %s define", filename, target_name); } else { - zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_LIB define", filename); + zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad %s define", filename, target_name); } return NULL; } p++; - if (*lib) { + if (*target) { if (preload) { - zend_error(E_WARNING, "FFI: failed pre-loading '%s', FFI_LIB defined twice", filename); + zend_error(E_WARNING, "FFI: failed pre-loading '%s', %s defined twice", filename, target_name); } else { - zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', FFI_LIB defined twice", filename); + zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', %s defined twice", filename, target_name); } return NULL; } - *lib = p; + *target = p; while (1) { if (*p == '\"') { *p = 0; @@ -5044,21 +5090,16 @@ static char *zend_ffi_parse_directives(const char *filename, char *code_pos, cha break; } else if (*p <= ' ') { if (preload) { - zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_LIB define", filename); + zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad %s define", filename, target_name); } else { - zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_LIB define", filename); + zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad %s define", filename, target_name); } return NULL; } p++; } - while (*p == ' ' || *p == '\t') { - p++; - } - while (*p == '\r' || *p == '\n') { - p++; - } - code_pos = p; + + code_pos = zend_ffi_skip_ws_and_comments(p, true); } else { break; } diff --git a/ext/ffi/tests/bug79075.h b/ext/ffi/tests/bug79075.h new file mode 100644 index 0000000000000..22fa6067a347a --- /dev/null +++ b/ext/ffi/tests/bug79075.h @@ -0,0 +1,12 @@ +/* + * Multiline comment + */ + // whitespace line + +#define ignore_this_line 1 + // +#define/* inline */FFI_SCOPE /* multi- +line */ "bug79075" /* end +*/ + +int printf(const char *format, ...); diff --git a/ext/ffi/tests/bug79075.inc b/ext/ffi/tests/bug79075.inc new file mode 100644 index 0000000000000..ab3daa93d4de3 --- /dev/null +++ b/ext/ffi/tests/bug79075.inc @@ -0,0 +1,3 @@ + +--INI-- +ffi.enable=1 +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.preload={PWD}/bug79075.inc +opcache.file_cache_only=0 +--FILE-- +printf("Hello World from %s!\n", "PHP"); +?> +--EXPECT-- +Hello World from PHP! diff --git a/ext/ffi/tests/gh16013.phpt b/ext/ffi/tests/gh16013.phpt new file mode 100644 index 0000000000000..be57846cc42bc --- /dev/null +++ b/ext/ffi/tests/gh16013.phpt @@ -0,0 +1,137 @@ +--TEST-- +GH-16013 (endianness issue with FFI) +--EXTENSIONS-- +ffi +zend_test +--FILE-- +bug_gh16013_return_char()); +var_dump($ffi->bug_gh16013_return_bool()); +var_dump($ffi->bug_gh16013_return_short()); +var_dump($ffi->bug_gh16013_return_int()); +var_dump($ffi->bug_gh16013_return_enum()); +var_dump($ffi->bug_gh16013_return_struct()); + +echo "--- Callback values ---\n"; +$bug_gh16013_callback_struct = $ffi->new('struct bug_gh16013_callback_struct'); +$bug_gh16013_callback_struct->return_int8 = function($val) use($ffi) { + $cdata = $ffi->new('int8_t'); + $cdata->cdata = $val; + return $cdata; +}; +$bug_gh16013_callback_struct->return_uint8 = function($val) use($ffi) { + $cdata = $ffi->new('uint8_t'); + $cdata->cdata = $val; + return $cdata; +}; +$bug_gh16013_callback_struct->return_int16 = function($val) use($ffi) { + $cdata = $ffi->new('int16_t'); + $cdata->cdata = $val; + return $cdata; +}; +$bug_gh16013_callback_struct->return_uint16 = function($val) use($ffi) { + $cdata = $ffi->new('uint16_t'); + $cdata->cdata = $val; + return $cdata; +}; +$bug_gh16013_callback_struct->return_int32 = function($val) use($ffi) { + $cdata = $ffi->new('int32_t'); + $cdata->cdata = $val; + return $cdata; +}; +$bug_gh16013_callback_struct->return_uint32 = function($val) use($ffi) { + $cdata = $ffi->new('uint32_t'); + $cdata->cdata = $val; + return $cdata; +}; +$bug_gh16013_callback_struct->return_float = function($val) use($ffi) { + $cdata = $ffi->new('float'); + $cdata->cdata = $val; + return $cdata; +}; +$bug_gh16013_callback_struct->return_struct = function($val) use($ffi) { + return $val; +}; +$bug_gh16013_callback_struct->return_enum = function($val) use($ffi) { + $cdata = $ffi->new('enum bug_gh16013_enum'); + $cdata->cdata = $val; + return $cdata; +}; + +var_dump(($bug_gh16013_callback_struct->return_int8)(-4)); +var_dump(($bug_gh16013_callback_struct->return_uint8)(4)); +var_dump(($bug_gh16013_callback_struct->return_int16)(-10000)); +var_dump(($bug_gh16013_callback_struct->return_uint16)(10000)); +var_dump(($bug_gh16013_callback_struct->return_int32)(-100000)); +var_dump(($bug_gh16013_callback_struct->return_uint32)(100000)); +var_dump(($bug_gh16013_callback_struct->return_float)(12.34)); +$struct = $ffi->new('struct bug_gh16013_int_struct'); +$struct->field = 10; +var_dump(($bug_gh16013_callback_struct->return_struct)($struct)); +var_dump(($bug_gh16013_callback_struct->return_enum)($ffi->BUG_GH16013_B)); +?> +--EXPECT-- +--- Return values --- +string(1) "A" +bool(true) +int(12345) +int(123456789) +int(2) +object(FFI\CData:struct bug_gh16013_int_struct)#2 (1) { + ["field"]=> + int(123456789) +} +--- Callback values --- +int(-4) +int(4) +int(-10000) +int(10000) +int(-100000) +int(100000) +float(12.34000015258789) +object(FFI\CData:struct bug_gh16013_int_struct)#13 (1) { + ["field"]=> + int(10) +} +int(2) diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c index 0ce2498f3a3a2..1bd9bad5afbe1 100644 --- a/ext/filter/logical_filters.c +++ b/ext/filter/logical_filters.c @@ -869,15 +869,120 @@ static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]) } /* }}} */ -void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ +/* From the tables in RFC 6890 - Special-Purpose IP Address Registriesi + * Including errata: https://www.rfc-editor.org/errata_search.php?rfc=6890&rec_status=1 */ +static bool ipv4_get_status_flags(const int ip[8], bool *global, bool *reserved, bool *private) +{ + *global = false; + *reserved = false; + *private = false; + + if (ip[0] == 0) { + /* RFC 0791 - This network */ + *reserved = true; + } else if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0) { + /* RFC 1122 - This host on this network */ + *reserved = true; + } else if (ip[0] == 10) { + /* RFC 1918 - Private Use */ + *private = true; + } else if (ip[0] == 100 && ip[1] >= 64 && ip[1] <= 127) { + /* RFC 6598 - Shared Address Space */ + } else if (ip[0] == 127) { + /* RFC 1122 - Loopback */ + *reserved = true; + } else if (ip[0] == 169 && ip[1] == 254) { + /* RFC 3927 - Link Local */ + *reserved = true; + } else if (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) { + /* RFC 1918 - Private Use */ + *private = true; + } else if (ip[0] == 192 && ip[1] == 0 && ip[2] == 0) { + /* RFC 6890 - IETF Protocol Assignments */ + } else if (ip[0] == 192 && ip[1] == 0 && ip[2] == 0 && ip[3] >= 0 && ip[3] <= 7) { + /* RFC 6333 - DS-Lite */ + } else if (ip[0] == 192 && ip[1] == 0 && ip[2] == 2) { + /* RFC 5737 - Documentation */ + } else if (ip[0] == 192 && ip[1] == 88 && ip[2] == 99) { + /* RFC 3068 - 6to4 Relay Anycast */ + *global = true; + } else if (ip[0] == 192 && ip[1] == 168) { + /* RFC 1918 - Private Use */ + *private = true; + } else if (ip[0] == 198 && ip[1] >= 18 && ip[1] <= 19) { + /* RFC 2544 - Benchmarking */ + } else if (ip[0] == 198 && ip[1] == 51 && ip[2] == 100) { + /* RFC 5737 - Documentation */ + } else if (ip[0] == 203 && ip[1] == 0 && ip[2] == 113) { + /* RFC 5737 - Documentation */ + } else if (ip[0] >= 240 && ip[1] <= 255) { + /* RFC 1122 - Reserved */ + *reserved = true; + } else if (ip[0] == 255 && ip[1] == 255 && ip[2] == 255 && ip[3] == 255) { + /* RFC 0919 - Limited Broadcast, Updated by RFC 8190, 2.2. */ + *reserved = true; + } else { + return false; + } + + return true; +} + +/* From the tables in RFC 6890 - Special-Purpose IP Address Registries */ +static bool ipv6_get_status_flags(const int ip[8], bool *global, bool *reserved, bool *private) { - /* validates an ipv4 or ipv6 IP, based on the flag (4, 6, or both) add a - * flag to throw out reserved ranges; multicast ranges... etc. If both - * allow_ipv4 and allow_ipv6 flags flag are used, then the first dot or - * colon determine the format */ + *global = false; + *reserved = false; + *private = false; + + if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && ip[7] == 0) { + /* RFC 4291 - Unspecified Address */ + *reserved = true; + } else if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && ip[7] == 1) { + /* RFC 4291 - Loopback Address */ + *reserved = true; + } else if (ip[0] == 0x0064 && ip[1] == 0xff9b) { + /* RFC 6052 - IPv4-IPv6 Translation */ + *global = true; + } else if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && ip[4] == 0 && ip[5] == 0xffff) { + /* RFC 4291 - IPv4-mapped Address */ + *reserved = true; + } else if (ip[0] == 0x0100 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0) { + /* RFC 6666 - Discard-Only Address Block */ + } else if (ip[0] == 0x2001 && ip[1] == 0x0000) { + /* RFC 4380 - TEREDO */ + } else if (ip[0] == 0x2001 && ip[1] <= 0x01ff) { + /* RFC 2928 - IETF Protocol Assignments */ + } else if (ip[0] == 0x2001 && ip[1] == 0x0002 && ip[2] == 0) { + /* RFC 5180 - Benchmarking */ + } else if (ip[0] == 0x2001 && ip[1] == 0x0db8) { + /* RFC 3849 - Documentation */ + } else if (ip[0] == 0x2001 && ip[1] >= 0x0010 && ip[1] <= 0x001f) { + /* RFC 4843 - ORCHID */ + } else if (ip[0] == 0x2002) { + /* RFC 3056 - 6to4 */ + } else if (ip[0] >= 0xfc00 && ip[0] <= 0xfdff) { + /* RFC 4193 - Unique-Local */ + *private = true; + } else if (ip[0] >= 0xfe80 && ip[0] <= 0xfebf) { + /* RFC 4291 - Linked-Scoped Unicast */ + *reserved = true; + } else { + return false; + } - int ip[8]; - int mode; + return true; +} + +/* Validates an ipv4 or ipv6 IP, based on the flag (4, 6, or both) add a flag + * to throw out reserved ranges; multicast ranges... etc. If both allow_ipv4 + * and allow_ipv6 flags flag are used, then the first dot or colon determine + * the format */ +void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ +{ + int ip[8]; + int mode; + bool flag_global, flag_reserved, flag_private; /* flags for ranges as determined by RFC 6890 */ if (memchr(Z_STRVAL_P(value), ':', Z_STRLEN_P(value))) { mode = FORMAT_IPV6; @@ -895,86 +1000,35 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ RETURN_VALIDATION_FAILED } - switch (mode) { - case FORMAT_IPV4: - if (!_php_filter_validate_ipv4(Z_STRVAL_P(value), Z_STRLEN_P(value), ip)) { - RETURN_VALIDATION_FAILED - } + if (mode == FORMAT_IPV4) { + if (!_php_filter_validate_ipv4(Z_STRVAL_P(value), Z_STRLEN_P(value), ip)) { + RETURN_VALIDATION_FAILED + } - /* Check flags */ - if (flags & FILTER_FLAG_NO_PRIV_RANGE || flags & FILTER_FLAG_GLOBAL_RANGE) { - if ( - (ip[0] == 10) || - (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) || - (ip[0] == 192 && ip[1] == 168) - ) { - RETURN_VALIDATION_FAILED - } - } + if (!ipv4_get_status_flags(ip, &flag_global, &flag_reserved, &flag_private)) { + return; /* no special block */ + } + } + else if (mode == FORMAT_IPV6) { + if (_php_filter_validate_ipv6(Z_STRVAL_P(value), Z_STRLEN_P(value), ip) < 1) { + RETURN_VALIDATION_FAILED + } - if (flags & FILTER_FLAG_NO_RES_RANGE || flags & FILTER_FLAG_GLOBAL_RANGE) { - if ( - (ip[0] == 0) || - (ip[0] >= 240) || - (ip[0] == 127) || - (ip[0] == 169 && ip[1] == 254) - ) { - RETURN_VALIDATION_FAILED - } - } + if (!ipv6_get_status_flags(ip, &flag_global, &flag_reserved, &flag_private)) { + return; /* no special block */ + } + } - if (flags & FILTER_FLAG_GLOBAL_RANGE) { - if ( - (ip[0] == 100 && ip[1] >= 64 && ip[1] <= 127 ) || - (ip[0] == 192 && ip[1] == 0 && ip[2] == 0 ) || - (ip[0] == 192 && ip[1] == 0 && ip[2] == 2 ) || - (ip[0] == 198 && ip[1] >= 18 && ip[1] <= 19 ) || - (ip[0] == 198 && ip[1] == 51 && ip[2] == 100 ) || - (ip[0] == 203 && ip[1] == 0 && ip[2] == 113 ) - ) { - RETURN_VALIDATION_FAILED - } - } + if ((flags & FILTER_FLAG_GLOBAL_RANGE) && flag_global != true) { + RETURN_VALIDATION_FAILED + } - break; + if ((flags & FILTER_FLAG_NO_PRIV_RANGE) && flag_private == true) { + RETURN_VALIDATION_FAILED + } - case FORMAT_IPV6: - { - int res = 0; - res = _php_filter_validate_ipv6(Z_STRVAL_P(value), Z_STRLEN_P(value), ip); - if (res < 1) { - RETURN_VALIDATION_FAILED - } - /* Check flags */ - if (flags & FILTER_FLAG_NO_PRIV_RANGE || flags & FILTER_FLAG_GLOBAL_RANGE) { - if (ip[0] >= 0xfc00 && ip[0] <= 0xfdff) { - RETURN_VALIDATION_FAILED - } - } - if (flags & FILTER_FLAG_NO_RES_RANGE || flags & FILTER_FLAG_GLOBAL_RANGE) { - if ( - (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && (ip[7] == 0 || ip[7] == 1)) || - (ip[0] == 0x5f) || - (ip[0] >= 0xfe80 && ip[0] <= 0xfebf) || - (ip[0] == 0x2001 && (ip[1] == 0x0db8 || (ip[1] >= 0x0010 && ip[1] <= 0x001f))) || - (ip[0] == 0x3ff3) - ) { - RETURN_VALIDATION_FAILED - } - } - if (flags & FILTER_FLAG_GLOBAL_RANGE) { - if ( - (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && ip[4] == 0 && ip[5] == 0xffff) || - (ip[0] == 0x0100 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0) || - (ip[0] == 0x2001 && ip[1] <= 0x01ff) || - (ip[0] == 0x2001 && ip[1] == 0x0002 && ip[2] == 0) || - (ip[0] >= 0xfc00 && ip[0] <= 0xfdff) - ) { - RETURN_VALIDATION_FAILED - } - } - } - break; + if ((flags & FILTER_FLAG_NO_RES_RANGE) && flag_reserved == true) { + RETURN_VALIDATION_FAILED } } /* }}} */ diff --git a/ext/filter/tests/PMOPB45.phpt b/ext/filter/tests/CVE-2007-1900.phpt similarity index 72% rename from ext/filter/tests/PMOPB45.phpt rename to ext/filter/tests/CVE-2007-1900.phpt index 9aba547539718..d18fd4e5026f5 100644 --- a/ext/filter/tests/PMOPB45.phpt +++ b/ext/filter/tests/CVE-2007-1900.phpt @@ -1,5 +1,5 @@ --TEST-- -PMOPB-45-2007:PHP ext/filter Email Validation Vulnerability +CVE-2007-1900: PHP ext/filter Email Validation Vulnerability --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/bug42718-2.phpt b/ext/filter/tests/bug42718-2.phpt index 675ce1a747d89..ad8383d85db2e 100644 --- a/ext/filter/tests/bug42718-2.phpt +++ b/ext/filter/tests/bug42718-2.phpt @@ -1,5 +1,5 @@ --TEST-- -Bug #42718 - 2 (unsafe_raw filter not applied when configured as default filter) +Bug #42718 (unsafe_raw filter not applied when configured as default filter) --EXTENSIONS-- filter --INI-- diff --git a/ext/filter/tests/bug47435.phpt b/ext/filter/tests/bug47435.phpt index b035bc0a5f69f..64ee6f7fe66f7 100644 --- a/ext/filter/tests/bug47435.phpt +++ b/ext/filter/tests/bug47435.phpt @@ -18,10 +18,6 @@ var_dump(filter_var("2001:0010::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)); var_dump(filter_var("2001:0010::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE)); var_dump(filter_var("240b:0010::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)); var_dump(filter_var("240b:0010::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE)); -var_dump(filter_var("5f::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)); -var_dump(filter_var("5f::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE)); -var_dump(filter_var("3ff3::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)); -var_dump(filter_var("3ff3::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE)); ?> --EXPECT-- string(7) "FC00::1" @@ -33,12 +29,8 @@ bool(false) string(11) "fe80:5:6::1" bool(false) string(12) "2001:0db8::1" -bool(false) +string(12) "2001:0db8::1" +string(12) "2001:0010::1" string(12) "2001:0010::1" -bool(false) string(12) "240b:0010::1" string(12) "240b:0010::1" -string(5) "5f::1" -bool(false) -string(7) "3ff3::1" -bool(false) diff --git a/ext/filter/tests/bug49274.phpt b/ext/filter/tests/bug49274.phpt index 12980db404177..3a2b434b0bc7d 100644 --- a/ext/filter/tests/bug49274.phpt +++ b/ext/filter/tests/bug49274.phpt @@ -1,5 +1,5 @@ --TEST-- -#49274, fatal error when an object does not implement toString +Bug #49274 (fatal error when an object does not implement toString) --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/bug49510.phpt b/ext/filter/tests/bug49510.phpt index 2a45915561161..b34afffcc03b9 100644 --- a/ext/filter/tests/bug49510.phpt +++ b/ext/filter/tests/bug49510.phpt @@ -1,5 +1,5 @@ --TEST-- -Bug #49510 boolean validation fails with FILTER_NULL_ON_FAILURE +Bug #49510 (boolean validation fails with FILTER_NULL_ON_FAILURE) --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/bug50632.phpt b/ext/filter/tests/bug50632.phpt index 5fa35c4d0bb69..07eae7aa54d35 100644 --- a/ext/filter/tests/bug50632.phpt +++ b/ext/filter/tests/bug50632.phpt @@ -1,5 +1,5 @@ --TEST-- -bug 50632, filter_input() does not return default value if the variable does not exist +Bug #50632 (filter_input() does not return default value if the variable does not exist) --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/bug51192.phpt b/ext/filter/tests/bug51192.phpt index 397f22d1d8817..fd4fd09c4422a 100644 --- a/ext/filter/tests/bug51192.phpt +++ b/ext/filter/tests/bug51192.phpt @@ -1,5 +1,5 @@ --TEST-- -bug 51192, FILTER_VALIDATE_URL will invalidate a hostname that includes '-' +Bug #51192 (FILTER_VALIDATE_URL will invalidate a hostname that includes '-') --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/bug51368.phpt b/ext/filter/tests/bug51368.phpt index 73c743b5dee4f..a7bc26d478122 100644 --- a/ext/filter/tests/bug51368.phpt +++ b/ext/filter/tests/bug51368.phpt @@ -1,5 +1,5 @@ --TEST-- -FR #51368 (php_filter_float does not allow custom thousand separators) +Bug #51368 (php_filter_float does not allow custom thousand separators) --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/bug64441.phpt b/ext/filter/tests/bug64441.phpt index 189f79d00c4ef..2dcc2a0f4fbcc 100644 --- a/ext/filter/tests/bug64441.phpt +++ b/ext/filter/tests/bug64441.phpt @@ -1,5 +1,5 @@ --TEST-- -bug 64441, FILTER_VALIDATE_URL will invalidate a hostname that ended by dot +Bug #64441 (FILTER_VALIDATE_URL will invalidate a hostname that ended by dot) --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/bug67167.01.phpt b/ext/filter/tests/bug67167.01.phpt index f51ccbe0dfc95..a55fabda304f1 100644 --- a/ext/filter/tests/bug67167.01.phpt +++ b/ext/filter/tests/bug67167.01.phpt @@ -1,5 +1,5 @@ --TEST-- -Bug #67167: object with VALIDATE_BOOLEAN and NULL_ON_FAILURE +Bug #67167 (object with VALIDATE_BOOLEAN and NULL_ON_FAILURE) --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/bug67167.02.phpt b/ext/filter/tests/bug67167.02.phpt index 62927309e62a4..acbb7eeca5fe7 100644 --- a/ext/filter/tests/bug67167.02.phpt +++ b/ext/filter/tests/bug67167.02.phpt @@ -1,5 +1,5 @@ --TEST-- -Bug #67167: filter_var(null,FILTER_VALIDATE_BOOLEAN,FILTER_NULL_ON_FAILURE) returns null +Bug #67167 (filter_var(null,FILTER_VALIDATE_BOOLEAN,FILTER_NULL_ON_FAILURE) returns null) --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/bug7715.phpt b/ext/filter/tests/bug7715.phpt index 7c31b30d91c4b..9855a723fe987 100644 --- a/ext/filter/tests/bug7715.phpt +++ b/ext/filter/tests/bug7715.phpt @@ -1,5 +1,5 @@ --TEST-- -bug 7715, floats value with integer or incomplete input +Bug #7715 (floats value with integer or incomplete input) --INI-- precision=14 --EXTENSIONS-- diff --git a/ext/filter/tests/bug7733.phpt b/ext/filter/tests/bug7733.phpt index a276d8a2b4a31..7a24decea2c54 100644 --- a/ext/filter/tests/bug7733.phpt +++ b/ext/filter/tests/bug7733.phpt @@ -1,5 +1,5 @@ --TEST-- -filter_var() Float exponential weird result +Bug #7733 (filter_var() Float exponential weird result) --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/bug80584.phpt b/ext/filter/tests/bug80584.phpt index 49fa71a921f05..9446c649f4bad 100644 --- a/ext/filter/tests/bug80584.phpt +++ b/ext/filter/tests/bug80584.phpt @@ -1,5 +1,5 @@ --TEST-- -Bug #80584: "0x" and "0X" are considered valid hex numbers by filter_var() +Bug #80584 ("0x" and "0X" are considered valid hex numbers by filter_var()) --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/bug8315.phpt b/ext/filter/tests/bug8315.phpt index e5334f43fc87f..55e1a745fa041 100644 --- a/ext/filter/tests/bug8315.phpt +++ b/ext/filter/tests/bug8315.phpt @@ -1,5 +1,5 @@ --TEST-- -bug 8315, NULL values halt the validation +Bug #8315 (NULL values halt the validation) --EXTENSIONS-- filter --FILE-- diff --git a/ext/filter/tests/gh16944.phpt b/ext/filter/tests/gh16944.phpt new file mode 100644 index 0000000000000..f6c492fed1abb --- /dev/null +++ b/ext/filter/tests/gh16944.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug GH-16944 (Invalid filtering of IPv6 with FILTER_FLAG_NO_RES_RANGE) +--EXTENSIONS-- +filter +--FILE-- + +--EXPECT-- +bool(false) diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 13da099b33506..847e0835bad4f 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -3433,7 +3433,24 @@ PHP_FUNCTION(imageconvolution) } } } - res = gdImageConvolution(im_src, matrix, (float)div, (float)offset); + + if (UNEXPECTED(!zend_finite(div))) { + zend_argument_value_error(3, "must be finite"); + RETURN_THROWS(); + } + + float div_float = (float) div; + if (UNEXPECTED(div_float == 0.0f)) { + zend_argument_value_error(3, "must not be 0"); + RETURN_THROWS(); + } + + if (UNEXPECTED(!zend_finite(offset))) { + zend_argument_value_error(4, "must be finite"); + RETURN_THROWS(); + } + + res = gdImageConvolution(im_src, matrix, div_float, (float) offset); if (res) { RETURN_TRUE; diff --git a/ext/gd/libgd/gd_bmp.c b/ext/gd/libgd/gd_bmp.c index a80904a62914d..27b5d11ae7683 100644 --- a/ext/gd/libgd/gd_bmp.c +++ b/ext/gd/libgd/gd_bmp.c @@ -350,9 +350,7 @@ static int compress_row(unsigned char *row, int length) } if (compressed_run) { - if (rle_type == BMP_RLE_TYPE_RLE) { - compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row); - } + compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row); } gdFree(uncompressed_start); diff --git a/ext/gd/tests/func.inc b/ext/gd/tests/func.inc index 5273f998300b1..0f10aa7d83dee 100644 --- a/ext/gd/tests/func.inc +++ b/ext/gd/tests/func.inc @@ -70,12 +70,8 @@ function get_libxpm_version() * message is printed, and the actual file is stored right beside the temporary * .php test file with the extension .out.png, to be able to manually inspect * the result. - * - * @param string $filename - * @param resource $actual - * @return void */ -function test_image_equals_file($filename, $actual) +function test_image_equals_file(string $filename, GdImage $actual): void { if (!file_exists($filename)) { echo "The expected image does not exist.\n"; @@ -85,13 +81,29 @@ function test_image_equals_file($filename, $actual) $actual = test_to_truecolor($actual); $expected = imagecreatefrompng($filename); $expected = test_to_truecolor($expected); + test_image_equals_image($expected, $actual, true); +} + +/** + * Tests that an in-memory image equals another in-memory image. + * + * It checks for equal image sizes, and whether any pixels are different. + * The textual result is printed, so the EXPECT section should contain the line + * "The images are equal." + * + * If the images are not equal, a diagnostic message is printed. + */ +function test_image_equals_image(GdImage $expected, GdImage $actual, bool $save_actual = false): void +{ $exp_x = imagesx($expected); $exp_y = imagesy($expected); $act_x = imagesx($actual); $act_y = imagesy($actual); if ($exp_x != $act_x || $exp_y != $act_y) { echo "The image size differs: expected {$exp_x}x{$exp_y}, got {$act_x}x{$act_y}.\n"; - save_actual_image($actual); + if ($save_actual) { + save_actual_image($actual); + } return; } $pixels_changed = 0; @@ -108,7 +120,9 @@ function test_image_equals_file($filename, $actual) echo "The images are equal.\n"; } else { echo "The images differ in {$pixels_changed} pixels.\n"; - save_actual_image($actual); + if ($save_actual) { + save_actual_image($actual); + } } } diff --git a/ext/gd/tests/gd276.phpt b/ext/gd/tests/gd276.phpt new file mode 100644 index 0000000000000..a12bce3983049 --- /dev/null +++ b/ext/gd/tests/gd276.phpt @@ -0,0 +1,26 @@ +--TEST-- +libgd bug 276 (Sometimes pixels are missing when storing images as BMPs) +--EXTENSIONS-- +gd +--FILE-- + +--EXPECT-- +bool(true) +The images are equal. +--CLEAN-- + diff --git a/ext/gd/tests/gh16255.phpt b/ext/gd/tests/gh16255.phpt new file mode 100644 index 0000000000000..147dc5adf377b --- /dev/null +++ b/ext/gd/tests/gh16255.phpt @@ -0,0 +1,34 @@ +--TEST-- +GH-16255 (Unexpected nan value in ext/gd/libgd/gd_filter.c) +--EXTENSIONS-- +gd +--CREDITS-- +cmb69 +--FILE-- +getMessage(), "\n"; +} + +try { + imageconvolution($im, $matrix, 2.225E-307, 1.0); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +try { + imageconvolution($im, $matrix, 1, NAN); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +imageconvolution(): Argument #3 ($divisor) must be finite +imageconvolution(): Argument #3 ($divisor) must not be 0 +imageconvolution(): Argument #4 ($offset) must be finite diff --git a/ext/gettext/config.m4 b/ext/gettext/config.m4 index 9e304d82b8d29..b3a6c35d6c006 100644 --- a/ext/gettext/config.m4 +++ b/ext/gettext/config.m4 @@ -25,6 +25,17 @@ if test "$PHP_GETTEXT" != "no"; then AC_CHECK_LIB(c, bindtextdomain, [ GETTEXT_LIBS= GETTEXT_CHECK_IN_LIB=c + + dnl If libintl.h is provided by libc, it's possible that libc is musl. + dnl The gettext family of functions under musl ignores the codeset + dnl suffix on directories like "en_US.UTF-8"; instead they look only + dnl in "en_US". To accomodate that, we symlink some test data from one + dnl to the other. + AC_MSG_NOTICE([symlinking en_US.UTF-8 messages to en_US in case you are on musl]) + _linkdest="${srcdir%/}"/ext/gettext/tests/locale/en_US + AS_IF([test ! -e "${_linkdest}"],[ + ln -s en_US.UTF-8 "${_linkdest}" + ]) ],[ AC_MSG_ERROR(Unable to find required gettext library) ]) diff --git a/ext/gettext/gettext.c b/ext/gettext/gettext.c index 15af3cb9b57ff..eba2a591e9f1b 100644 --- a/ext/gettext/gettext.c +++ b/ext/gettext/gettext.c @@ -167,7 +167,7 @@ PHP_FUNCTION(bindtextdomain) char *domain; size_t domain_len; zend_string *dir = NULL; - char *retval, dir_name[MAXPATHLEN]; + char *retval, dir_name[MAXPATHLEN], *btd_result; if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS!", &domain, &domain_len, &dir) == FAILURE) { RETURN_THROWS(); @@ -181,7 +181,16 @@ PHP_FUNCTION(bindtextdomain) } if (dir == NULL) { - RETURN_STRING(bindtextdomain(domain, NULL)); + btd_result = bindtextdomain(domain, NULL); + if (btd_result == NULL) { + /* POSIX-compliant implementations can return + * NULL if an error occured. On musl you will + * also get NULL if the domain is not yet + * bound, because musl has no default directory + * to return in that case. */ + RETURN_FALSE; + } + RETURN_STRING(btd_result); } if (ZSTR_LEN(dir) != 0 && !zend_string_equals_literal(dir, "0")) { diff --git a/ext/gettext/tests/bug53251.phpt b/ext/gettext/tests/bug53251.phpt index 6f37642925d37..d568be6bc079a 100644 --- a/ext/gettext/tests/bug53251.phpt +++ b/ext/gettext/tests/bug53251.phpt @@ -8,18 +8,28 @@ if (getenv('SKIP_REPEAT')) die('skip gettext leaks global state across requests' ?> --FILE-- --EXPECT-- bool(true) -bool(true) -bool(false) -string(5) "UTF-8" -string(5) "UTF-8" diff --git a/ext/gettext/tests/gettext_bind_textdomain_codeset-retval.phpt b/ext/gettext/tests/gettext_bind_textdomain_codeset-retval.phpt index 47c821648fccb..941bab79bffa2 100644 --- a/ext/gettext/tests/gettext_bind_textdomain_codeset-retval.phpt +++ b/ext/gettext/tests/gettext_bind_textdomain_codeset-retval.phpt @@ -5,13 +5,21 @@ gettext --FILE-- --EXPECT-- bool(false) -string(5) "UTF-8" +bool(true) Done --CREDITS-- Florian Holzhauer fh-pt@fholzhauer.de diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c index 75f78dd174238..8ac3bc9b3c480 100644 --- a/ext/iconv/iconv.c +++ b/ext/iconv/iconv.c @@ -2536,7 +2536,8 @@ static php_stream_filter_status_t php_iconv_stream_filter_do_filter( if (php_iconv_stream_filter_append_bucket(self, stream, filter, buckets_out, bucket->buf, bucket->buflen, &consumed, php_stream_is_persistent(stream)) != SUCCESS) { - goto out_failure; + php_stream_bucket_delref(bucket); + return PSFS_ERR_FATAL; } php_stream_bucket_delref(bucket); @@ -2546,7 +2547,7 @@ static php_stream_filter_status_t php_iconv_stream_filter_do_filter( if (php_iconv_stream_filter_append_bucket(self, stream, filter, buckets_out, NULL, 0, &consumed, php_stream_is_persistent(stream)) != SUCCESS) { - goto out_failure; + return PSFS_ERR_FATAL; } } @@ -2555,12 +2556,6 @@ static php_stream_filter_status_t php_iconv_stream_filter_do_filter( } return PSFS_PASS_ON; - -out_failure: - if (bucket != NULL) { - php_stream_bucket_delref(bucket); - } - return PSFS_ERR_FATAL; } /* }}} */ diff --git a/ext/iconv/tests/gh17047.phpt b/ext/iconv/tests/gh17047.phpt new file mode 100644 index 0000000000000..a0307ddbe5553 --- /dev/null +++ b/ext/iconv/tests/gh17047.phpt @@ -0,0 +1,17 @@ +--TEST-- +GH-17047 (UAF on iconv filter failure) +--EXTENSIONS-- +iconv +--FILE-- + +--EXPECTF-- +Warning: stream_get_contents(): iconv stream filter ("UTF-16BE"=>"UTF-16BE"): invalid multibyte sequence in %s on line %d +string(0) "" diff --git a/ext/intl/config.w32 b/ext/intl/config.w32 index ab7dc42b66246..567d29dc5a786 100644 --- a/ext/intl/config.w32 +++ b/ext/intl/config.w32 @@ -3,7 +3,10 @@ ARG_ENABLE("intl", "Enable internationalization support", "no"); if (PHP_INTL != "no") { - if (CHECK_LIB("icuuc.lib", "intl", PHP_INTL) && + if (CHECK_LIB("icudt.lib", "intl", PHP_INTL) && + CHECK_LIB("icuin.lib", "intl", PHP_INTL) && + CHECK_LIB("icuio.lib", "intl", PHP_INTL) && + CHECK_LIB("icuuc.lib", "intl", PHP_INTL) && CHECK_HEADER_ADD_INCLUDE("unicode/utf.h", "CFLAGS_INTL")) { // always build as shared - zend_strtod.c/ICU type conflict EXTENSION("intl", "php_intl.c intl_convert.c intl_convertcpp.cpp intl_error.c ", true, @@ -115,16 +118,9 @@ if (PHP_INTL != "no") { codepointiterator_methods.cpp ", "intl"); - ADD_FLAG("LIBS_INTL", "icudt.lib icuin.lib icuio.lib"); - /* Compat for ICU before 58.1.*/ - if (CHECK_LIB("icule.lib", "intl", PHP_INTL)) { - ADD_FLAG("LIBS_INTL", "icule.lib"); - } - if (CHECK_LIB("iculx.lib", "intl", PHP_INTL)) { - ADD_FLAG("LIBS_INTL", "iculx.lib"); - } - + CHECK_LIB("icule.lib", "intl", PHP_INTL); + CHECK_LIB("iculx.lib", "intl", PHP_INTL); ADD_FLAG("CFLAGS_INTL", "/EHsc /DUNISTR_FROM_CHAR_EXPLICIT=explicit /DUNISTR_FROM_STRING_EXPLICIT=explicit /DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 /DU_HIDE_OBSOLETE_UTF_OLD_H=1"); AC_DEFINE("HAVE_INTL", 1, "Internationalization support enabled"); } else { diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index 0def911c0a3b2..e66ff070577bd 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -235,6 +235,22 @@ static void ldap_result_entry_free_obj(zend_object *obj) } \ } +static bool php_ldap_is_numerically_indexed_array(zend_array *arr) +{ + if (zend_hash_num_elements(arr) == 0 || HT_IS_PACKED(arr)) { + return true; + } + + zend_string *str_key; + ZEND_HASH_MAP_FOREACH_STR_KEY(arr, str_key) { + if (str_key) { + return false; + } + } ZEND_HASH_FOREACH_END(); + + return false; +} + /* {{{ Parse controls from and to arrays */ static void _php_ldap_control_to_array(LDAP *ld, LDAPControl* ctrl, zval* array, int request) { @@ -1471,20 +1487,22 @@ static void php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS, int scope) num_attribs = zend_hash_num_elements(Z_ARRVAL_P(attrs)); ldap_attrs = safe_emalloc((num_attribs+1), sizeof(char *), 0); - for (i = 0; imod_bvalues[0]->bv_val = Z_STRVAL_P(value); ldap_mods[i]->mod_bvalues[0]->bv_len = Z_STRLEN_P(value); } else { - for (j = 0; j < num_values; j++) { - if ((ivalue = zend_hash_index_find(Z_ARRVAL_P(value), j)) == NULL) { - zend_argument_value_error(3, "must contain arrays with consecutive integer indices starting from 0"); - num_berval[i] = j; - num_attribs = i + 1; - RETVAL_FALSE; - goto cleanup; - } + if (!php_ldap_is_numerically_indexed_array(Z_ARRVAL_P(value))) { + zend_argument_value_error(3, "must be an array with numeric keys"); + RETVAL_FALSE; + num_berval[i] = 0; + num_attribs = i + 1; + goto cleanup; + } + + j = 0; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(value), ivalue) { convert_to_string(ivalue); if (EG(exception)) { num_berval[i] = j; @@ -2275,7 +2295,8 @@ static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper, int ext) ldap_mods[i]->mod_bvalues[j] = (struct berval *) emalloc (sizeof(struct berval)); ldap_mods[i]->mod_bvalues[j]->bv_val = Z_STRVAL_P(ivalue); ldap_mods[i]->mod_bvalues[j]->bv_len = Z_STRLEN_P(ivalue); - } + j++; + } ZEND_HASH_FOREACH_END(); } ldap_mods[i]->mod_bvalues[num_values] = NULL; zend_hash_move_forward(Z_ARRVAL_P(entry)); @@ -2543,7 +2564,7 @@ PHP_FUNCTION(ldap_modify_batch) zval *fetched; char *dn; size_t dn_len; - int i, j, k; + int i, j; int num_mods, num_modprops, num_modvals; LDAPMod **ldap_mods; LDAPControl **lserverctrls = NULL; @@ -2603,12 +2624,14 @@ PHP_FUNCTION(ldap_modify_batch) num_mods = zend_hash_num_elements(Z_ARRVAL_P(mods)); - for (i = 0; i < num_mods; i++) { - /* is the numbering consecutive? */ - if ((fetched = zend_hash_index_find(Z_ARRVAL_P(mods), i)) == NULL) { - zend_argument_value_error(3, "must have consecutive integer indices starting from 0"); - RETURN_THROWS(); - } + if (!php_ldap_is_numerically_indexed_array(Z_ARRVAL_P(mods))) { + zend_argument_value_error(3, "must be an array with numeric keys"); + RETURN_THROWS(); + } + + i = 0; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(mods), fetched) { + ZVAL_DEREF(fetched); mod = fetched; /* is it an array? */ @@ -2706,19 +2729,10 @@ PHP_FUNCTION(ldap_modify_batch) RETURN_THROWS(); } - /* are its keys integers? */ - if (zend_hash_get_current_key_type(Z_ARRVAL_P(modinfo)) != HASH_KEY_IS_LONG) { - zend_value_error("%s(): Option \"" LDAP_MODIFY_BATCH_VALUES "\" must be integer-indexed", get_active_function_name()); + if (!php_ldap_is_numerically_indexed_array(Z_ARRVAL_P(modinfo))) { + zend_value_error("%s(): Option \"" LDAP_MODIFY_BATCH_VALUES "\" must be an array with numeric keys", get_active_function_name()); RETURN_THROWS(); } - - /* are the keys consecutive? */ - for (k = 0; k < num_modvals; k++) { - if ((fetched = zend_hash_index_find(Z_ARRVAL_P(modinfo), k)) == NULL) { - zend_value_error("%s(): Option \"" LDAP_MODIFY_BATCH_VALUES "\" must have consecutive integer indices starting from 0", get_active_function_name()); - RETURN_THROWS(); - } - } } zend_hash_move_forward(Z_ARRVAL_P(mod)); @@ -2732,7 +2746,9 @@ PHP_FUNCTION(ldap_modify_batch) zend_value_error("%s(): Required option \"" LDAP_MODIFY_BATCH_MODTYPE "\" is missing", get_active_function_name()); RETURN_THROWS(); } - } + + i++; + } ZEND_HASH_FOREACH_END(); } /* validation was successful */ @@ -2786,9 +2802,9 @@ PHP_FUNCTION(ldap_modify_batch) ldap_mods[i]->mod_bvalues = safe_emalloc((num_modvals+1), sizeof(struct berval *), 0); /* for each value */ - for (j = 0; j < num_modvals; j++) { + j = 0; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(vals), fetched) { /* fetch it */ - fetched = zend_hash_index_find(Z_ARRVAL_P(vals), j); modval = zval_get_string(fetched); if (EG(exception)) { RETVAL_FALSE; @@ -2804,7 +2820,8 @@ PHP_FUNCTION(ldap_modify_batch) ldap_mods[i]->mod_bvalues[j]->bv_len = ZSTR_LEN(modval); ldap_mods[i]->mod_bvalues[j]->bv_val = estrndup(ZSTR_VAL(modval), ZSTR_LEN(modval)); zend_string_release(modval); - } + j++; + } ZEND_HASH_FOREACH_END(); /* NULL-terminate values */ ldap_mods[i]->mod_bvalues[num_modvals] = NULL; diff --git a/ext/ldap/tests/gh17280.phpt b/ext/ldap/tests/gh17280.phpt new file mode 100644 index 0000000000000..8c75f1276ab58 --- /dev/null +++ b/ext/ldap/tests/gh17280.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-17280 (ldap_search() fails when $attributes array has holes) +--EXTENSIONS-- +ldap +--FILE-- + +--EXPECTF-- +Warning: ldap_search(): Search: Can't contact LDAP server in %s on line %d +bool(false) diff --git a/ext/ldap/tests/ldap_add_error.phpt b/ext/ldap/tests/ldap_add_error.phpt index d78276eca3e54..5036b3091e835 100644 --- a/ext/ldap/tests/ldap_add_error.phpt +++ b/ext/ldap/tests/ldap_add_error.phpt @@ -43,7 +43,7 @@ try { ldap_add($link, "dc=my-domain2,dc=com", array( "objectClass" => array( 0 => "top", - 2 => "dcObject", + "x" => "dcObject", 5 => "organization"), "dc" => "my-domain", "o" => "my-domain", @@ -104,7 +104,7 @@ Warning: ldap_add(): Add: Already exists in %s on line %d bool(false) string(14) "Already exists" int(68) -ldap_add(): Argument #3 ($entry) must contain arrays with consecutive integer indices starting from 0 +ldap_add(): Argument #3 ($entry) must be an array with numeric keys Warning: ldap_add(): Add: Undefined attribute type in %s on line %d bool(false) diff --git a/ext/ldap/tests/ldap_search_error.phpt b/ext/ldap/tests/ldap_search_error.phpt index 659b8a6c0664b..be07f5409ef7b 100644 --- a/ext/ldap/tests/ldap_search_error.phpt +++ b/ext/ldap/tests/ldap_search_error.phpt @@ -19,7 +19,7 @@ $filter = "(dc=*)"; $result = ldap_search($link, $dn, $filter); var_dump($result); -$result = ldap_search($link, $dn, $filter, array(1 => 'top')); +$result = ldap_search($link, $dn, $filter, array('foo' => 'top')); var_dump($result); try { @@ -57,7 +57,7 @@ try { Warning: ldap_search(): Search: No such object in %s on line %d bool(false) -Warning: ldap_search(): Array initialization wrong in %s on line %d +Warning: ldap_search(): Argument #4 ($attributes) must be an array with numeric keys in %s on line %d bool(false) ldap_search(): Argument #1 ($ldap) cannot be empty ldap_search(): Argument #2 ($base) must have the same number of elements as the links array diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 0c252e5e455aa..6590f73f9edd6 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -590,11 +590,11 @@ php_libxml_output_buffer_create_filename(const char *URI, char *unescaped = NULL; if (URI == NULL) - return(NULL); + goto err; if (strstr(URI, "%00")) { php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes"); - return NULL; + goto err; } puri = xmlParseURI(URI); @@ -615,7 +615,7 @@ php_libxml_output_buffer_create_filename(const char *URI, } if (context == NULL) { - return(NULL); + goto err; } /* Allocate the Output buffer front-end. */ @@ -627,6 +627,11 @@ php_libxml_output_buffer_create_filename(const char *URI, } return(ret); + +err: + /* Similarly to __xmlOutputBufferCreateFilename we should also close the encoder on failure. */ + xmlCharEncCloseFunc(encoder); + return NULL; } static void _php_libxml_free_error(void *ptr) diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h b/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h index b25ec71eef9de..2072b848bd5bd 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h +++ b/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h @@ -31,9 +31,9 @@ #ifndef MBFL_ENCODING_H #define MBFL_ENCODING_H +#include "zend.h" #include "mbfl_defs.h" #include "mbfl_consts.h" -#include "zend.h" enum mbfl_no_encoding { mbfl_no_encoding_invalid = -1, diff --git a/ext/mysqli/tests/fake_server.inc b/ext/mysqli/tests/fake_server.inc index 1127f6c00e3f9..d6afbb0497734 100644 --- a/ext/mysqli/tests/fake_server.inc +++ b/ext/mysqli/tests/fake_server.inc @@ -615,9 +615,11 @@ class my_mysqli_fake_server_conn class my_mysqli_fake_server_process { + private int $port; + public function __construct(private $process, private array $pipes) {} - public function terminate(bool $wait = false) + public function terminate(bool $wait = false): void { if ($wait) { $this->wait(); @@ -625,9 +627,18 @@ class my_mysqli_fake_server_process proc_terminate($this->process); } - public function wait() + public function wait(): void { - echo fgets($this->pipes[1]); + $line = fgets($this->pipes[1]); + if (preg_match('/\[\*\] Server started on \d+\.\d+\.\d+\.\d+:(\d+)/', $line, $matches)) { + $this->port = (int)$matches[1]; + } + echo $line; + } + + public function getPort(): int + { + return $this->port ?? throw new RuntimeException("Port not set"); } } @@ -807,15 +818,20 @@ function my_mysqli_test_query_response_row_read_two_fields(my_mysqli_fake_server } } -function run_fake_server(string $test_function, $port = 33305): void +function run_fake_server(string $test_function, int|string $port = 0): int { - $address = '127.0.0.1'; + $host = '127.0.0.1'; - $socket = @stream_socket_server("tcp://$address:$port", $errno, $errstr); + $socket = @stream_socket_server("tcp://$host:$port", $errno, $errstr); if (!$socket) { die("Failed to create socket: $errstr ($errno)\n"); } - echo "[*] Server started\n"; + if (intval($port) === 0) { + $address = stream_socket_get_name($socket, false); + list($host, $port) = explode(":", $address); + } + + echo "[*] Server started on $host:$port\n"; try { $conn = new my_mysqli_fake_server_conn($socket); @@ -832,7 +848,7 @@ function run_fake_server(string $test_function, $port = 33305): void } -function run_fake_server_in_background($test_function, $port = 33305): my_mysqli_fake_server_process +function run_fake_server_in_background($test_function, $port = 0): my_mysqli_fake_server_process { $command = [PHP_BINARY, '-n', __FILE__, 'mysqli_fake_server', $test_function, $port]; @@ -852,5 +868,5 @@ function run_fake_server_in_background($test_function, $port = 33305): my_mysqli } if (isset($argv) && $argc > 2 && $argv[1] == 'mysqli_fake_server') { - run_fake_server($argv[2], $argv[3] ?? '33305'); + run_fake_server($argv[2], $argv[3] ?? 0); } diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt index 279aec6a2cba1..666f47f4199fb 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt @@ -6,16 +6,15 @@ mysqli wait(); try { - $conn = new mysqli( $servername, $username, $password, "", $port ); + $conn = new mysqli( $servername, $username, $password, "", $process->getPort()); $info = mysqli_info($conn); var_dump($info); } catch (Exception $e) { @@ -27,12 +26,12 @@ $process->terminate(); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 [*] Sending - Malicious OK Auth Response [Extract heap through buffer over-read]: 0900000200000002000000fcff Warning: mysqli::__construct(): OK packet message length is past the packet size in %s on line %d -Unknown error while trying to connect via tcp://127.0.0.1:33305 +Unknown error while trying to connect via tcp://127.0.0.1:%d done! diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt index 77f2232eca687..0883962321d20 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt @@ -6,16 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Running query on the fake server...\n"; @@ -34,7 +32,7 @@ $process->terminate(); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt index 0b4db8ccece95..c397399a278a9 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Running query on the fake server...\n"; $result = $conn->query("SELECT * from users"); @@ -27,7 +26,7 @@ $process->terminate(); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt index f141a79bdaa85..797acbedff9ad 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Query the fake server...\n"; $sql = "SELECT strval, strval FROM data"; @@ -33,7 +32,7 @@ $process->terminate(true); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt index e43518217eb63..bf64bb62d1e66 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Preparing statement on the fake server...\n"; $stmt = $conn->prepare("SELECT bitval, timval FROM data"); @@ -36,7 +35,7 @@ $process->terminate(true); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt index 76158e940d09d..99a7381994ae8 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Preparing statement on the fake server...\n"; $stmt = $conn->prepare("SELECT strval, datval FROM data"); @@ -36,7 +35,7 @@ $process->terminate(true); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt index f53d5b83bd432..c6b9bd79fa981 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Preparing statement on the fake server...\n"; $stmt = $conn->prepare("SELECT strval, dtival FROM data"); @@ -36,7 +35,7 @@ $process->terminate(true); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt index 03c9b045d7375..460321d2ee5d5 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Preparing statement on the fake server...\n"; $stmt = $conn->prepare("SELECT strval, dblval FROM data"); @@ -36,7 +35,7 @@ $process->terminate(true); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt index b1ec9aa51eca1..a1ea19bb4f6b7 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Preparing statement on the fake server...\n"; $stmt = $conn->prepare("SELECT strval, fltval FROM data"); @@ -36,7 +35,7 @@ $process->terminate(true); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt index 426d9ea7b3f9b..839fadb21f0e2 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Preparing statement on the fake server...\n"; $stmt = $conn->prepare("SELECT strval, intval FROM data"); @@ -36,7 +35,7 @@ $process->terminate(true); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt index 6db6952d42a15..ce028483dec21 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Preparing statement on the fake server...\n"; $stmt = $conn->prepare("SELECT strval, strval FROM data"); @@ -36,7 +35,7 @@ $process->terminate(true); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt index 55bad4cc544aa..e40ed1d58c7ff 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Preparing statement on the fake server...\n"; $stmt = $conn->prepare("SELECT item FROM items"); @@ -36,7 +35,7 @@ $process->terminate(true); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt index 06918c375f31a..6aa58898a8d55 100644 --- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt +++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); echo "[*] Preparing statement on the fake server...\n"; $stmt = $conn->prepare("SELECT strval, timval FROM data"); @@ -36,7 +35,7 @@ $process->terminate(true); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/protocol_query_row_fetch_data.phpt b/ext/mysqli/tests/protocol_query_row_fetch_data.phpt index 524fe5e587c63..22f9712ef7fb0 100644 --- a/ext/mysqli/tests/protocol_query_row_fetch_data.phpt +++ b/ext/mysqli/tests/protocol_query_row_fetch_data.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); function my_query($conn, $field) { @@ -39,8 +38,8 @@ $process->terminate(true); print "done!"; ?> ---EXPECT-- -[*] Server started +--EXPECTF-- +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt b/ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt index af16a9eb2d05f..6e689f9d2be5f 100644 --- a/ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt +++ b/ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt @@ -6,15 +6,14 @@ mysqli wait(); -$conn = new mysqli($servername, $username, $password, "", $port); +$conn = new mysqli($servername, $username, $password, "", $process->getPort()); function my_query($conn, $field) { @@ -41,7 +40,7 @@ $process->terminate(true); print "done!"; ?> --EXPECTF-- -[*] Server started +[*] Server started on 127.0.0.1:%d [*] Connection established [*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264 [*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31 diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index fb886d39e60ac..66c10021442ad 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -2153,7 +2153,10 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type) */ from_shared_memory = false; if (persistent_script) { + /* See GH-17246: we disable GC so that user code cannot be executed during the optimizer run. */ + bool orig_gc_state = gc_enable(false); persistent_script = cache_script_in_shared_memory(persistent_script, key, &from_shared_memory); + gc_enable(orig_gc_state); } /* Caching is disabled, returning op_array; diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 33277958843bf..f1c52bcc976e3 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -9274,19 +9274,11 @@ static int zend_jit_init_fcall_guard(dasm_State **Dst, uint32_t level, const zen int32_t exit_point; const void *exit_addr; - if (func->type == ZEND_INTERNAL_FUNCTION) { -#ifdef ZEND_WIN32 - // TODO: ASLR may cause different addresses in different workers ??? - return 0; -#endif - } else if (func->type == ZEND_USER_FUNCTION) { + if (func->type == ZEND_USER_FUNCTION) { if (!zend_accel_in_shm(func->op_array.opcodes)) { /* op_array and op_array->opcodes are not persistent. We can't link. */ return 0; } - } else { - ZEND_UNREACHABLE(); - return 0; } exit_point = zend_jit_trace_get_exit_point(to_opline, ZEND_JIT_EXIT_POLYMORPHISM); @@ -9320,6 +9312,22 @@ static int zend_jit_init_fcall_guard(dasm_State **Dst, uint32_t level, const zen | cmp aword [r1 + offsetof(zend_op_array, opcodes)], opcodes | .endif | jne &exit_addr +#ifdef _WIN32 + } else if (func->type == ZEND_INTERNAL_FUNCTION) { + const zif_handler handler = func->internal_function.handler; + + | .if X64 + || if (!IS_SIGNED_32BIT(handler)) { + | mov64 r2, ((ptrdiff_t)handler) + | cmp aword [r1 + offsetof(zend_internal_function, handler)], r2 + || } else { + | cmp aword [r1 + offsetof(zend_internal_function, handler)], handler + || } + | .else + | cmp aword [r1 + offsetof(zend_internal_function, handler)], handler + | .endif + | jne &exit_addr +#endif } else { | .if X64 || if (!IS_SIGNED_32BIT(func)) { @@ -9466,6 +9474,22 @@ static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t | cmp aword [r0 + offsetof(zend_op_array, opcodes)], opcodes | .endif | jz >3 +#ifdef _WIN32 + } else if (func->type == ZEND_INTERNAL_FUNCTION) { + const zif_handler handler = func->internal_function.handler; + + | .if X64 + || if (!IS_SIGNED_32BIT(handler)) { + | mov64 r1, ((ptrdiff_t)handler) + | cmp aword [r0 + offsetof(zend_internal_function, handler)], r1 + || } else { + | cmp aword [r0 + offsetof(zend_internal_function, handler)], handler + || } + | .else + | cmp aword [r0 + offsetof(zend_internal_function, handler)], handler + | .endif + | jz >3 +#endif } else { | .if X64 || if (!IS_SIGNED_32BIT(func)) { @@ -9652,11 +9676,7 @@ static int zend_jit_init_method_call(dasm_State **Dst, if ((!func || zend_jit_may_be_modified(func, op_array)) && trace && trace->op == ZEND_JIT_TRACE_INIT_CALL - && trace->func -#ifdef _WIN32 - && trace->func->type != ZEND_INTERNAL_FUNCTION -#endif - ) { + && trace->func) { int32_t exit_point; const void *exit_addr; @@ -9685,6 +9705,22 @@ static int zend_jit_init_method_call(dasm_State **Dst, | cmp aword [r0 + offsetof(zend_op_array, opcodes)], opcodes | .endif | jne &exit_addr +#ifdef _WIN32 + } else if (func->type == ZEND_INTERNAL_FUNCTION) { + const zif_handler handler = func->internal_function.handler; + + | .if X64 + || if (!IS_SIGNED_32BIT(handler)) { + | mov64 r1, ((ptrdiff_t)handler) + | cmp aword [r0 + offsetof(zend_internal_function, handler)], r1 + || } else { + | cmp aword [r0 + offsetof(zend_internal_function, handler)], handler + || } + | .else + | cmp aword [r0 + offsetof(zend_internal_function, handler)], handler + | .endif + | jne &exit_addr +#endif } else { | .if X64 || if (!IS_SIGNED_32BIT(func)) { diff --git a/ext/opcache/tests/gh17106.phpt b/ext/opcache/tests/gh17106.phpt new file mode 100644 index 0000000000000..5b56131b5a29f --- /dev/null +++ b/ext/opcache/tests/gh17106.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-17106: ZEND_MATCH_ERROR misoptimization +--EXTENSIONS-- +opcache +--INI-- +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- + 2 }); +var_dump(match (X) { 2 => 2 }); + +?> +--EXPECT-- +int(7) +int(2) +int(2) diff --git a/ext/opcache/tests/jit/gh17246.inc b/ext/opcache/tests/jit/gh17246.inc new file mode 100644 index 0000000000000..f9e7d78fc165a --- /dev/null +++ b/ext/opcache/tests/jit/gh17246.inc @@ -0,0 +1,8 @@ +field = function() {}; + } + + public function __destruct() + { + // Necessary because we need to invoke tracing JIT during destruction + } +} + +for ($i = 0; $i < 10000; ++$i) { + $obj = new Test(); +} + +require __DIR__.'/gh17246.inc'; + +?> +--EXPECTF-- +Fatal error: Uncaught Error: Class "NonExistentClass" not found in %s:%d +Stack trace: +#0 %s(%d): require() +#1 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/jit/gh9011.phpt b/ext/opcache/tests/jit/gh9011.phpt new file mode 100644 index 0000000000000..3ffefe2ce29be --- /dev/null +++ b/ext/opcache/tests/jit/gh9011.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-9011: Assertion failure with tracing JIT +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +--FILE-- +__toString(); + } +} +?> +DONE +--EXPECT-- +DONE \ No newline at end of file diff --git a/ext/opcache/tests/opcache_jit_prof_threshold.phpt b/ext/opcache/tests/opcache_jit_prof_threshold.phpt new file mode 100644 index 0000000000000..f98c12b99ba91 --- /dev/null +++ b/ext/opcache/tests/opcache_jit_prof_threshold.phpt @@ -0,0 +1,19 @@ +--TEST-- +opcache_get_configuration() properly reports jit_prof_threshold +--EXTENSIONS-- +opcache +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +float(0.0078125) +bool(true) diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 5c69c9f7883a2..90936929f8447 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -849,7 +849,7 @@ ZEND_FUNCTION(opcache_get_configuration) add_assoc_long(&directives, "opcache.jit_max_recursive_returns", JIT_G(max_recursive_returns)); add_assoc_long(&directives, "opcache.jit_max_root_traces", JIT_G(max_root_traces)); add_assoc_long(&directives, "opcache.jit_max_side_traces", JIT_G(max_side_traces)); - add_assoc_long(&directives, "opcache.jit_prof_threshold", JIT_G(prof_threshold)); + add_assoc_double(&directives, "opcache.jit_prof_threshold", JIT_G(prof_threshold)); add_assoc_long(&directives, "opcache.jit_max_trace_length", JIT_G(max_trace_length)); #endif diff --git a/ext/openssl/tests/ServerClientTestCase.inc b/ext/openssl/tests/ServerClientTestCase.inc index 0d67d7f7b2d85..8eedbfdebee8b 100644 --- a/ext/openssl/tests/ServerClientTestCase.inc +++ b/ext/openssl/tests/ServerClientTestCase.inc @@ -4,14 +4,19 @@ const WORKER_ARGV_VALUE = 'RUN_WORKER'; const WORKER_DEFAULT_NAME = 'server'; -function phpt_notify($worker = WORKER_DEFAULT_NAME) +function phpt_notify(string $worker = WORKER_DEFAULT_NAME, string $message = ""): void { - ServerClientTestCase::getInstance()->notify($worker); + ServerClientTestCase::getInstance()->notify($worker, $message); } -function phpt_wait($worker = WORKER_DEFAULT_NAME, $timeout = null) +function phpt_wait($worker = WORKER_DEFAULT_NAME, $timeout = null): ?string { - ServerClientTestCase::getInstance()->wait($worker, $timeout); + return ServerClientTestCase::getInstance()->wait($worker, $timeout); +} + +function phpt_notify_server_start($server): void +{ + ServerClientTestCase::getInstance()->notify_server_start($server); } function phpt_has_sslv3() { @@ -149,43 +154,73 @@ class ServerClientTestCase eval($code); } - public function run($masterCode, $workerCode) + /** + * Run client and all workers + * + * @param string $clientCode The client PHP code + * @param string|array $workerCode + * @param bool $ephemeral Select whether automatic port selection and automatic awaiting is used + * @return void + * @throws Exception + */ + public function run(string $clientCode, string|array $workerCode, bool $ephemeral = true): void { if (!is_array($workerCode)) { $workerCode = [WORKER_DEFAULT_NAME => $workerCode]; } - foreach ($workerCode as $worker => $code) { + reset($workerCode); + $code = current($workerCode); + $worker = key($workerCode); + while ($worker != null) { $this->spawnWorkerProcess($worker, $this->stripPhpTagsFromCode($code)); + $code = next($workerCode); + if ($ephemeral) { + $addr = trim($this->wait($worker)); + if (empty($addr)) { + throw new \Exception("Failed server start"); + } + if ($code === false) { + $clientCode = preg_replace('/{{\s*ADDR\s*}}/', $addr, $clientCode); + } else { + $code = preg_replace('/{{\s*ADDR\s*}}/', $addr, $code); + } + } + $worker = key($workerCode); } - eval($this->stripPhpTagsFromCode($masterCode)); + + eval($this->stripPhpTagsFromCode($clientCode)); foreach ($workerCode as $worker => $code) { $this->cleanupWorkerProcess($worker); } } - public function wait($worker, $timeout = null) + public function wait($worker, $timeout = null): ?string { $handle = $this->isWorker ? STDIN : $this->workerStdOut[$worker]; if ($timeout === null) { - fgets($handle); - return true; + return fgets($handle); } stream_set_blocking($handle, false); $read = [$handle]; $result = stream_select($read, $write, $except, $timeout); if (!$result) { - return false; + return null; } - fgets($handle); + $result = fgets($handle); stream_set_blocking($handle, true); - return true; + return $result; + } + + public function notify(string $worker, string $message = ""): void + { + fwrite($this->isWorker ? STDOUT : $this->workerStdIn[$worker], "$message\n"); } - public function notify($worker) + public function notify_server_start($server): void { - fwrite($this->isWorker ? STDOUT : $this->workerStdIn[$worker], "\n"); + echo stream_socket_get_name($server, false) . "\n"; } } diff --git a/ext/openssl/tests/bug46127.phpt b/ext/openssl/tests/bug46127.phpt index 72b7bd7488611..7c38192fca95a 100644 --- a/ext/openssl/tests/bug46127.phpt +++ b/ext/openssl/tests/bug46127.phpt @@ -11,14 +11,14 @@ if (!function_exists("proc_open")) die("skip no proc_open"); $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug46127.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', ]]); $sock = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($sock); $link = stream_socket_accept($sock); fwrite($link, "Sending bug 46127\n"); @@ -26,7 +26,7 @@ CODE; $serverCode = sprintf($serverCode, $certFile); $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ @@ -34,7 +34,6 @@ $clientCode = <<<'CODE' 'verify_peer_name' => false ]]); - phpt_wait(); $sock = stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx); echo fgets($sock); diff --git a/ext/openssl/tests/bug48182.phpt b/ext/openssl/tests/bug48182.phpt index b5fa518a8f4d2..057b257038f2a 100644 --- a/ext/openssl/tests/bug48182.phpt +++ b/ext/openssl/tests/bug48182.phpt @@ -12,14 +12,14 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug48182.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug48182-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); $client = @stream_socket_accept($server, 1); @@ -30,14 +30,13 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'bug48182'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'cafile' => '%s', 'peer_name' => '%s' ]]); - phpt_wait(); $client = stream_socket_client($serverUri, $errno, $errstr, 10, $clientFlags, $clientCtx); $data = "Sending data over to SSL server in async mode with contents like Hello World\n"; diff --git a/ext/openssl/tests/bug54992.phpt b/ext/openssl/tests/bug54992.phpt index 5cf65ff7a05b8..bc5df171c5f07 100644 --- a/ext/openssl/tests/bug54992.phpt +++ b/ext/openssl/tests/bug54992.phpt @@ -12,14 +12,14 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug54992.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug54992-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); CODE; @@ -28,7 +28,7 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'bug54992_actual_peer_name'; $wrongPeerName = 'bug54992_expected_peer_name'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, @@ -36,7 +36,6 @@ $clientCode = <<<'CODE' 'peer_name' => '%s', ]]); - phpt_wait(); $client = stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx); var_dump($client); @@ -61,5 +60,5 @@ Warning: stream_socket_client(): Peer certificate CN=`bug54992_actual_peer_name' Warning: stream_socket_client(): Failed to enable crypto in %s on line %d -Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:%d (Unknown error) in %s on line %d bool(false) diff --git a/ext/openssl/tests/bug62890.phpt b/ext/openssl/tests/bug62890.phpt index f8b3ee860519d..aa9bec0e69630 100644 --- a/ext/openssl/tests/bug62890.phpt +++ b/ext/openssl/tests/bug62890.phpt @@ -19,8 +19,8 @@ $serverCode = <<<'CODE' 'security_level' => 1, ]]); - $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); @stream_socket_accept($server, 3); CODE; $serverCode = sprintf($serverCode, $certFile); @@ -33,9 +33,7 @@ $clientCode = <<<'CODE' 'security_level' => 1, ]]); - phpt_wait(); - - $client = stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); CODE; diff --git a/ext/openssl/tests/bug65538_001.phpt b/ext/openssl/tests/bug65538_001.phpt index c6f443627b53e..e04f6cf820e4c 100644 --- a/ext/openssl/tests/bug65538_001.phpt +++ b/ext/openssl/tests/bug65538_001.phpt @@ -12,14 +12,14 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug65538_001.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug65538_001-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); $client = @stream_socket_accept($server); if ($client) { @@ -41,13 +41,12 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'bug65538_001'; $clientCode = <<<'CODE' - $serverUri = "https://127.0.0.1:64321/"; + $serverUri = "https://{{ ADDR }}/"; $clientCtx = stream_context_create(['ssl' => [ 'cafile' => 'file://%s', 'peer_name' => '%s', ]]); - phpt_wait(); $html = file_get_contents($serverUri, false, $clientCtx); var_dump($html); diff --git a/ext/openssl/tests/bug65538_003.phpt b/ext/openssl/tests/bug65538_003.phpt index 3b16b7b030c68..c18a024f0761d 100644 --- a/ext/openssl/tests/bug65538_003.phpt +++ b/ext/openssl/tests/bug65538_003.phpt @@ -17,14 +17,14 @@ $cacertFile = 'bug65538_003-ca.pem'; $cacertPhar = __DIR__ . DIRECTORY_SEPARATOR . 'bug65538_003-ca.phar.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); $client = @stream_socket_accept($server); if ($client) { @@ -46,13 +46,12 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'bug65538_003'; $clientCode = <<<'CODE' - $serverUri = "https://127.0.0.1:64321/"; + $serverUri = "https://{{ ADDR }}/"; $clientCtx = stream_context_create(['ssl' => [ 'cafile' => 'phar://%s/%s', 'peer_name' => '%s', ]]); - phpt_wait(); $html = file_get_contents($serverUri, false, $clientCtx); var_dump($html); diff --git a/ext/openssl/tests/bug65729.phpt b/ext/openssl/tests/bug65729.phpt index 21d2ac7f569cc..6df22fd4a7aac 100644 --- a/ext/openssl/tests/bug65729.phpt +++ b/ext/openssl/tests/bug65729.phpt @@ -12,14 +12,14 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug65729.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug65729-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); $expected_names = ['foo.test.com.sg', 'foo.test.com', 'FOO.TEST.COM', 'foo.bar.test.com']; foreach ($expected_names as $name) { @@ -29,11 +29,9 @@ CODE; $serverCode = sprintf($serverCode, $certFile); $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; - phpt_wait(); - $expected_names = ['foo.test.com.sg', 'foo.test.com', 'FOO.TEST.COM', 'foo.bar.test.com']; foreach ($expected_names as $expected_name) { $clientCtx = stream_context_create(['ssl' => [ @@ -65,7 +63,7 @@ Warning: stream_socket_client(): Peer certificate CN=`*.test.com' did not match Warning: stream_socket_client(): Failed to enable crypto in %s on line %d -Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:%d (Unknown error) in %s on line %d bool(false) resource(%d) of type (stream) resource(%d) of type (stream) @@ -74,5 +72,5 @@ Warning: stream_socket_client(): Peer certificate CN=`*.test.com' did not match Warning: stream_socket_client(): Failed to enable crypto in %s on line %d -Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:%d (Unknown error) in %s on line %d bool(false) diff --git a/ext/openssl/tests/bug68265.phpt b/ext/openssl/tests/bug68265.phpt index 9d72d47707edf..ca82543520ca8 100644 --- a/ext/openssl/tests/bug68265.phpt +++ b/ext/openssl/tests/bug68265.phpt @@ -12,21 +12,21 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug68265.pem.tmp'; $san = 'DNS:debs.ak-online.be., DNS:debs.ak-online.net.'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); stream_socket_accept($server, 30); CODE; $serverCode = sprintf($serverCode, $certFile); $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => false, @@ -34,8 +34,6 @@ $clientCode = <<<'CODE' 'peer_name' => 'debs.ak-online.net', ]]); - phpt_wait(); - var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); CODE; diff --git a/ext/openssl/tests/bug68879.phpt b/ext/openssl/tests/bug68879.phpt index b529b93e7f438..cf87d2b543760 100644 --- a/ext/openssl/tests/bug68879.phpt +++ b/ext/openssl/tests/bug68879.phpt @@ -12,21 +12,21 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug68879.pem.tmp'; $san = 'DNS:test.com, DNS:www.test.com, DNS:subdomain.test.com, IP:0:0:0:0:0:FFFF:A02:1, IP:10.2.0.1'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); stream_socket_accept($server, 30); CODE; $serverCode = sprintf($serverCode, $certFile); $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => false, @@ -34,8 +34,6 @@ $clientCode = <<<'CODE' 'peer_name' => '10.2.0.1', ]]); - phpt_wait(); - var_dump(stream_socket_client($serverUri, $errno, $errstr, 30, $clientFlags, $clientCtx)); CODE; diff --git a/ext/openssl/tests/bug68920.phpt b/ext/openssl/tests/bug68920.phpt index b25dd715dbb5c..4abe12586b0b8 100644 --- a/ext/openssl/tests/bug68920.phpt +++ b/ext/openssl/tests/bug68920.phpt @@ -11,14 +11,14 @@ if (!function_exists("proc_open")) die("skip no proc_open"); $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug68920.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); stream_socket_accept($server, 30); stream_socket_accept($server, 30); @@ -28,11 +28,9 @@ CODE; $serverCode = sprintf($serverCode, $certFile); $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; - phpt_wait(); - $ctx = stream_context_create(['ssl' => ['verify_peer'=> false, 'peer_fingerprint' => true]]); $sock = stream_socket_client($serverUri, $errno, $errstr, 30, $clientFlags, $ctx); var_dump($sock); diff --git a/ext/openssl/tests/bug69215.phpt b/ext/openssl/tests/bug69215.phpt index fcae9c19a9e65..8b5dc5a261f31 100644 --- a/ext/openssl/tests/bug69215.phpt +++ b/ext/openssl/tests/bug69215.phpt @@ -13,7 +13,7 @@ $clientCertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug69215-client.pem.tmp'; $serverCertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug69215-server.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', @@ -24,14 +24,14 @@ $serverCode = <<<'CODE' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); stream_socket_accept($server, 30); CODE; $serverCode = sprintf($serverCode, $serverCertFile, $caCertFile); $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', @@ -41,8 +41,6 @@ $clientCode = <<<'CODE' 'peer_name' => 'bug69215-server', ]]); - phpt_wait(); - var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); CODE; $clientCode = sprintf($clientCode, $clientCertFile, $caCertFile); diff --git a/ext/openssl/tests/bug72333.phpt b/ext/openssl/tests/bug72333.phpt index d484db77f02cf..57faf4d8fc99c 100644 --- a/ext/openssl/tests/bug72333.phpt +++ b/ext/openssl/tests/bug72333.phpt @@ -14,8 +14,8 @@ $serverCode = <<<'CODE' $context = stream_context_create(['ssl' => ['local_cert' => '%s']]); $flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN; - $fp = stream_socket_server("ssl://127.0.0.1:10011", $errornum, $errorstr, $flags, $context); - phpt_notify(); + $fp = stream_socket_server("ssl://127.0.0.1:0", $errornum, $errorstr, $flags, $context); + phpt_notify_server_start($fp); $conn = stream_socket_accept($fp); $total = 100000; $result = fread($conn, $total); @@ -40,8 +40,7 @@ $peerName = 'bug72333'; $clientCode = <<<'CODE' $context = stream_context_create(['ssl' => ['verify_peer' => false, 'peer_name' => '%s']]); - phpt_wait(); - $fp = stream_socket_client("ssl://127.0.0.1:10011", $errornum, $errorstr, 3000, STREAM_CLIENT_CONNECT, $context); + $fp = stream_socket_client("ssl://{{ ADDR }}", $errornum, $errorstr, 3000, STREAM_CLIENT_CONNECT, $context); stream_set_blocking($fp, false); function blocking_fwrite($fp, $buf) { diff --git a/ext/openssl/tests/bug73072.phpt b/ext/openssl/tests/bug73072.phpt index 953dc74efbeae..881de20937f25 100644 --- a/ext/openssl/tests/bug73072.phpt +++ b/ext/openssl/tests/bug73072.phpt @@ -18,9 +18,9 @@ $serverCode = <<<'CODE' ] ]]); - $server = stream_socket_server('tls://127.0.0.1:64322', $errno, $errstr, $flags, $ctx); + $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); - phpt_notify(); @stream_socket_accept($server, 3); // if there is a segfault, this won't be called fwrite(STDERR, "done\n"); @@ -33,11 +33,9 @@ $clientCode = <<<'CODE' 'capture_peer_cert' => true ]; - phpt_wait(); - $ctxArr['peer_name'] = 'domain1.com'; $ctx = stream_context_create(['ssl' => $ctxArr]); - @stream_socket_client("tls://127.0.0.1:64322", $errno, $errstr, 1, $flags, $ctx); + @stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 1, $flags, $ctx); CODE; include 'ServerClientTestCase.inc'; diff --git a/ext/openssl/tests/bug74159.phpt b/ext/openssl/tests/bug74159.phpt index 92bdba10d27d4..523169e364a80 100644 --- a/ext/openssl/tests/bug74159.phpt +++ b/ext/openssl/tests/bug74159.phpt @@ -15,7 +15,7 @@ $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug74159-ca.pem.tmp'; // not really reliable on more powerful machine but cover different // scenarios which might be useful. More reliable test is bug72333.phpt $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:10012"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', @@ -23,7 +23,7 @@ $serverCode = <<<'CODE' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); $client = stream_socket_accept($server, 1); @@ -73,7 +73,7 @@ $clientCode = <<<'CODE' exit("$errstr\n"); }); - $serverUri = "tcp://127.0.0.1:10012"; + $serverUri = "tcp://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, @@ -81,8 +81,6 @@ $clientCode = <<<'CODE' 'peer_name' => '%s', ]]); - phpt_wait(); - $fp = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); stream_set_blocking($fp, false); diff --git a/ext/openssl/tests/bug76705.phpt b/ext/openssl/tests/bug76705.phpt index 0ff9a563932ee..6e898c57b64fa 100644 --- a/ext/openssl/tests/bug76705.phpt +++ b/ext/openssl/tests/bug76705.phpt @@ -9,20 +9,20 @@ if (!function_exists("proc_open")) die("skip no proc_open"); --FILE-- [ 'local_cert' => __DIR__ . '/bug76705.pem' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); CODE; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64323"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, @@ -33,7 +33,6 @@ $clientCode = <<<'CODE' ] ]]); - phpt_wait(); var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); CODE; diff --git a/ext/openssl/tests/bug77390.phpt b/ext/openssl/tests/bug77390.phpt index b45910b766492..a55ee16f4bf02 100644 --- a/ext/openssl/tests/bug77390.phpt +++ b/ext/openssl/tests/bug77390.phpt @@ -15,11 +15,7 @@ $peerName = 'bug77390'; $clientCode = <<<'CODE' $context = stream_context_create(['ssl' => ['verify_peer' => false, 'peer_name' => '%s']]); - phpt_wait('server'); - phpt_notify('proxy'); - - phpt_wait('proxy'); - $fp = stream_socket_client("ssl://127.0.0.1:10012", $errornum, $errorstr, 3000, STREAM_CLIENT_CONNECT, $context); + $fp = stream_socket_client("ssl://{{ ADDR }}", $errornum, $errorstr, 3000, STREAM_CLIENT_CONNECT, $context); stream_set_blocking($fp, false); $read = [$fp]; @@ -57,8 +53,8 @@ $serverCode = <<<'CODE' $context = stream_context_create(['ssl' => ['local_cert' => '%s']]); $flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN; - $fp = stream_socket_server("ssl://127.0.0.1:10011", $errornum, $errorstr, $flags, $context); - phpt_notify(); + $fp = stream_socket_server("ssl://127.0.0.1:0", $errornum, $errorstr, $flags, $context); + phpt_notify_server_start($fp); $conn = stream_socket_accept($fp); fwrite($conn, 'warmup'); @@ -71,14 +67,12 @@ 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); + $upstream = stream_socket_client("tcp://{{ ADDR }}", $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(); + $server = stream_socket_server("tcp://127.0.0.1:0", $errornum, $errorstr, $flags); + phpt_notify_server_start($server); $conn = stream_socket_accept($server); stream_set_blocking($conn, false); diff --git a/ext/openssl/tests/capture_peer_cert_001.phpt b/ext/openssl/tests/capture_peer_cert_001.phpt index dc1e2caa6a973..bbf9e6d2c5f5d 100644 --- a/ext/openssl/tests/capture_peer_cert_001.phpt +++ b/ext/openssl/tests/capture_peer_cert_001.phpt @@ -12,14 +12,14 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'capture_peer_cert_001.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'capture_peer_cert_001-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); CODE; @@ -27,14 +27,13 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'capture_peer_cert_001'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'capture_peer_cert' => true, 'cafile' => '%s' ]]); - phpt_wait(); $client = @stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); $cert = stream_context_get_options($clientCtx)['ssl']['peer_certificate']; var_dump(openssl_x509_parse($cert)['subject']['CN']); diff --git a/ext/openssl/tests/gh10495.phpt b/ext/openssl/tests/gh10495.phpt index 7c743d8de50a5..5ef4894890c1c 100644 --- a/ext/openssl/tests/gh10495.phpt +++ b/ext/openssl/tests/gh10495.phpt @@ -15,11 +15,7 @@ $peerName = 'gh10495'; $clientCode = <<<'CODE' $context = stream_context_create(['ssl' => ['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); + $fp = stream_socket_client("tlsv1.2://{{ ADDR }}", $errornum, $errorstr, 1, STREAM_CLIENT_CONNECT, $context); phpt_wait('proxy'); @@ -38,8 +34,8 @@ $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(); + $fp = stream_socket_server("tlsv1.2://127.0.0.1:0", $errornum, $errorstr, $flags, $context); + phpt_notify_server_start($fp); $conn = stream_socket_accept($fp); fwrite($conn, 'warmup'); @@ -50,14 +46,12 @@ 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); + $upstream = stream_socket_client("tcp://{{ ADDR }}", $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(); + $server = stream_socket_server("tcp://127.0.0.1:0", $errornum, $errorstr, $flags); + phpt_notify_server_start($server); $conn = stream_socket_accept($server); stream_set_blocking($conn, false); diff --git a/ext/openssl/tests/gh13860.phpt b/ext/openssl/tests/gh13860.phpt index aff0df15cca95..35eb473fe12d8 100644 --- a/ext/openssl/tests/gh13860.phpt +++ b/ext/openssl/tests/gh13860.phpt @@ -9,12 +9,12 @@ if (!function_exists("proc_open")) die("skip no proc_open"); --FILE-- [ 'local_cert' => '%s', @@ -37,13 +37,13 @@ $serverCodeTemplate = <<<'CODE' ]]); $sock = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($sock); $link = stream_socket_accept($sock); CODE; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ @@ -51,7 +51,6 @@ $clientCode = <<<'CODE' 'verify_peer_name' => false ]]); - phpt_wait(); @stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx); CODE; @@ -65,8 +64,8 @@ $sniServerCodeV1 = <<<'CODE' ] ]]); - $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); stream_socket_accept($server); CODE; @@ -84,8 +83,8 @@ $sniServerCodeV2 = <<<'CODE' ] ]]); - $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); stream_socket_accept($server); CODE; @@ -103,8 +102,8 @@ $sniServerCodeV3 = <<<'CODE' ] ]]); - $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); stream_socket_accept($server); CODE; @@ -115,11 +114,9 @@ $sniClientCodeTemplate = <<<'CODE' 'cafile' => __DIR__ . '/sni_server_ca.pem', ]; - phpt_wait(); - $ctxArr['peer_name'] = '%s'; $ctx = stream_context_create(['ssl' => $ctxArr]); - @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + @stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 1, $flags, $ctx); CODE; $serverCode = sprintf($serverCodeTemplate, $baseDirCertFile . "\0test", $baseDirPkFile); diff --git a/ext/openssl/tests/openssl_peer_fingerprint_basic.phpt b/ext/openssl/tests/openssl_peer_fingerprint_basic.phpt index fb2c852160c18..34080446088d2 100644 --- a/ext/openssl/tests/openssl_peer_fingerprint_basic.phpt +++ b/ext/openssl/tests/openssl_peer_fingerprint_basic.phpt @@ -12,14 +12,14 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'openssl_peer_fingerprint_basic.pem. $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'openssl_peer_fingerprint_basic-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); @stream_socket_accept($server, 1); @@ -28,7 +28,7 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'openssl_peer_fingerprint_basic'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, @@ -37,8 +37,6 @@ $clientCode = <<<'CODE' 'peer_name' => '%s', ]]); - phpt_wait(); - stream_context_set_option($clientCtx, 'ssl', 'peer_fingerprint', '%s'); var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); @@ -75,6 +73,6 @@ Warning: stream_socket_client(): peer_fingerprint match failure in %s on line %d Warning: stream_socket_client(): Failed to enable crypto in %s on line %d -Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:%d (Unknown error) in %s on line %d bool(false) resource(%d) of type (stream) diff --git a/ext/openssl/tests/peer_verification.phpt b/ext/openssl/tests/peer_verification.phpt index 3ca5f8e14136d..bda68c933ca4d 100644 --- a/ext/openssl/tests/peer_verification.phpt +++ b/ext/openssl/tests/peer_verification.phpt @@ -12,14 +12,14 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'peer_verification.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'peer_verification-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); for ($i = 0; $i < 5; $i++) { @stream_socket_accept($server, 1); @@ -29,12 +29,10 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'peer_verification'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $caFile = '%s'; - phpt_wait(); - // Expected to fail -- untrusted server cert and no CA File present var_dump(@stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags)); diff --git a/ext/openssl/tests/san_ipv6_peer_matching.phpt b/ext/openssl/tests/san_ipv6_peer_matching.phpt index 81966025d3969..bc3bd02f269cd 100644 --- a/ext/openssl/tests/san_ipv6_peer_matching.phpt +++ b/ext/openssl/tests/san_ipv6_peer_matching.phpt @@ -17,14 +17,14 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'san_ipv6_peer_matching.pem.tmp'; $san = 'IP:2001:db8:85a3:8d3:1319:8a2e:370:7348'; $serverCode = <<<'CODE' - $serverUri = "ssl://[::1]:64324"; + $serverUri = "ssl://[::1]:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); @stream_socket_accept($server, 1); @@ -32,14 +32,12 @@ CODE; $serverCode = sprintf($serverCode, $certFile); $clientCode = <<<'CODE' - $serverUri = "ssl://[::1]:64324"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => false, ]]); - phpt_wait(); - stream_context_set_option($clientCtx, 'ssl', 'peer_name', '2001:db8:85a3:8d3:1319:8a2e:370:7348'); var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); @@ -65,5 +63,5 @@ Warning: stream_socket_client(): Unable to locate peer certificate CN in %s on l Warning: stream_socket_client(): Failed to enable crypto in %s on line %d -Warning: stream_socket_client(): Unable to connect to ssl://[::1]:64324 (Unknown error) in %s on line %d +Warning: stream_socket_client(): Unable to connect to ssl://[::1]:%d (Unknown error) in %s on line %d bool(false) diff --git a/ext/openssl/tests/san_peer_matching.phpt b/ext/openssl/tests/san_peer_matching.phpt index cc828fe004bb5..0df18f4a92505 100644 --- a/ext/openssl/tests/san_peer_matching.phpt +++ b/ext/openssl/tests/san_peer_matching.phpt @@ -12,14 +12,14 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'san_peer_matching.pem.tmp'; $san = 'DNS:example.org, DNS:www.example.org, DNS:test.example.org'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); @stream_socket_accept($server, 1); @@ -27,14 +27,12 @@ CODE; $serverCode = sprintf($serverCode, $certFile); $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => false, ]]); - phpt_wait(); - stream_context_set_option($clientCtx, 'ssl', 'peer_name', 'example.org'); var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); @@ -60,5 +58,5 @@ Warning: stream_socket_client(): Unable to locate peer certificate CN in %s on l Warning: stream_socket_client(): Failed to enable crypto in %s on line %d -Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:%d (Unknown error) in %s on line %d bool(false) diff --git a/ext/openssl/tests/session_meta_capture.phpt b/ext/openssl/tests/session_meta_capture.phpt index 36e3855f80aac..c642126a12693 100644 --- a/ext/openssl/tests/session_meta_capture.phpt +++ b/ext/openssl/tests/session_meta_capture.phpt @@ -12,7 +12,7 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'session_meta_capture.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'session_meta_capture-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', @@ -20,7 +20,7 @@ $serverCode = <<<'CODE' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); @stream_socket_accept($server, 1); @@ -31,7 +31,7 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'session_meta_capture'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, @@ -40,8 +40,6 @@ $clientCode = <<<'CODE' 'security_level' => 0, ]]); - phpt_wait(); - stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT); $stream = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); var_dump(stream_get_meta_data($stream)['crypto']['protocol']); diff --git a/ext/openssl/tests/session_meta_capture_tlsv13.phpt b/ext/openssl/tests/session_meta_capture_tlsv13.phpt index e07fb8c24e478..a21813d95031e 100644 --- a/ext/openssl/tests/session_meta_capture_tlsv13.phpt +++ b/ext/openssl/tests/session_meta_capture_tlsv13.phpt @@ -13,7 +13,7 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'session_meta_capture_tlsv13.pem.tmp $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'session_meta_capture_tlsv13-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', @@ -21,7 +21,7 @@ $serverCode = <<<'CODE' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); CODE; @@ -29,7 +29,7 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'session_meta_capture_tlsv13'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, @@ -37,8 +37,6 @@ $clientCode = <<<'CODE' 'peer_name' => '%s' ]]); - phpt_wait(); - stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT); $stream = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); var_dump(stream_get_meta_data($stream)['crypto']['protocol']); @@ -53,5 +51,10 @@ $certificateGenerator->saveNewCertAsFileWithKey($peerName, $certFile); include 'ServerClientTestCase.inc'; ServerClientTestCase::getInstance()->run($clientCode, $serverCode); ?> +--CLEAN-- + --EXPECT-- string(7) "TLSv1.3" diff --git a/ext/openssl/tests/sni_server.phpt b/ext/openssl/tests/sni_server.phpt index ecfcf7a8172ea..7f9a4e82872b4 100644 --- a/ext/openssl/tests/sni_server.phpt +++ b/ext/openssl/tests/sni_server.phpt @@ -18,8 +18,8 @@ $serverCode = <<<'CODE' ] ]]); - $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); for ($i=0; $i < 3; $i++) { @stream_socket_accept($server, 3); @@ -33,23 +33,21 @@ $clientCode = <<<'CODE' 'capture_peer_cert' => true ]; - phpt_wait(); - $ctxArr['peer_name'] = 'cs.php.net'; $ctx = stream_context_create(['ssl' => $ctxArr]); - $client = stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $client = stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 1, $flags, $ctx); $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; var_dump(openssl_x509_parse($cert)['subject']['CN']); $ctxArr['peer_name'] = 'uk.php.net'; $ctx = stream_context_create(['ssl' => $ctxArr]); - $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $client = @stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 1, $flags, $ctx); $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; var_dump(openssl_x509_parse($cert)['subject']['CN']); $ctxArr['peer_name'] = 'us.php.net'; $ctx = stream_context_create(['ssl' => $ctxArr]); - $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $client = @stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 1, $flags, $ctx); $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; var_dump(openssl_x509_parse($cert)['subject']['CN']); CODE; diff --git a/ext/openssl/tests/sni_server_key_cert.phpt b/ext/openssl/tests/sni_server_key_cert.phpt index a4e1f5e42a312..49ed6aa5328cc 100644 --- a/ext/openssl/tests/sni_server_key_cert.phpt +++ b/ext/openssl/tests/sni_server_key_cert.phpt @@ -27,8 +27,8 @@ $serverCode = <<<'CODE' ] ]]); - $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); for ($i=0; $i < 3; $i++) { @stream_socket_accept($server, 3); @@ -42,23 +42,21 @@ $clientCode = <<<'CODE' 'capture_peer_cert' => true ]; - phpt_wait(); - $ctxArr['peer_name'] = 'cs.php.net'; $ctx = stream_context_create(['ssl' => $ctxArr]); - $client = stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $client = stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 1, $flags, $ctx); $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; var_dump(openssl_x509_parse($cert)['subject']['CN']); $ctxArr['peer_name'] = 'uk.php.net'; $ctx = stream_context_create(['ssl' => $ctxArr]); - $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $client = @stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 1, $flags, $ctx); $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; var_dump(openssl_x509_parse($cert)['subject']['CN']); $ctxArr['peer_name'] = 'us.php.net'; $ctx = stream_context_create(['ssl' => $ctxArr]); - $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $client = @stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 1, $flags, $ctx); $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; var_dump(openssl_x509_parse($cert)['subject']['CN']); CODE; diff --git a/ext/openssl/tests/stream_crypto_flags_001.phpt b/ext/openssl/tests/stream_crypto_flags_001.phpt index 74caacc2ea91e..ed22864a32e5e 100644 --- a/ext/openssl/tests/stream_crypto_flags_001.phpt +++ b/ext/openssl/tests/stream_crypto_flags_001.phpt @@ -12,7 +12,7 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_crypto_flags_001.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_crypto_flags_001-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', @@ -20,7 +20,7 @@ $serverCode = <<<'CODE' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); @stream_socket_accept($server, 1); @@ -30,7 +30,7 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'stream_crypto_flags_001'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, @@ -39,8 +39,6 @@ $clientCode = <<<'CODE' 'security_level' => 0, ]]); - phpt_wait(); - stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT); var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); diff --git a/ext/openssl/tests/stream_crypto_flags_002.phpt b/ext/openssl/tests/stream_crypto_flags_002.phpt index 870fd00e581bf..8b73f883c3fd7 100644 --- a/ext/openssl/tests/stream_crypto_flags_002.phpt +++ b/ext/openssl/tests/stream_crypto_flags_002.phpt @@ -12,7 +12,7 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_crypto_flags_002.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_crypto_flags_002-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', @@ -20,7 +20,7 @@ $serverCode = <<<'CODE' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); @stream_socket_accept($server, 1); @@ -31,7 +31,7 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'stream_crypto_flags_002'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, @@ -40,8 +40,6 @@ $clientCode = <<<'CODE' 'security_level' => 0, ]]); - phpt_wait(); - stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT); var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); diff --git a/ext/openssl/tests/stream_crypto_flags_003.phpt b/ext/openssl/tests/stream_crypto_flags_003.phpt index a75dd18cf6a74..a112fcff0b9d2 100644 --- a/ext/openssl/tests/stream_crypto_flags_003.phpt +++ b/ext/openssl/tests/stream_crypto_flags_003.phpt @@ -13,7 +13,7 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_crypto_flags_003.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_crypto_flags_003-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', @@ -24,7 +24,7 @@ $serverCode = <<<'CODE' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); @stream_socket_accept($server, 1); @@ -35,7 +35,7 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'stream_crypto_flags_003'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, @@ -44,8 +44,6 @@ $clientCode = <<<'CODE' 'security_level' => 0, ]]); - phpt_wait(); - stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT); var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); diff --git a/ext/openssl/tests/stream_crypto_flags_004.phpt b/ext/openssl/tests/stream_crypto_flags_004.phpt index 0a2fbc123dfd8..cfd54c9bc1c8b 100644 --- a/ext/openssl/tests/stream_crypto_flags_004.phpt +++ b/ext/openssl/tests/stream_crypto_flags_004.phpt @@ -12,7 +12,7 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_crypto_flags_004.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_crypto_flags_004-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', @@ -21,7 +21,7 @@ $serverCode = <<<'CODE' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); @stream_socket_accept($server, 1); @@ -32,7 +32,7 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'stream_crypto_flags_004'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, @@ -41,8 +41,6 @@ $clientCode = <<<'CODE' 'security_level' => 0, ]]); - phpt_wait(); - // Should succeed because the SSLv23 handshake here is compatible with the // TLSv1 hello method employed in the server var_dump(@stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); diff --git a/ext/openssl/tests/stream_security_level.phpt b/ext/openssl/tests/stream_security_level.phpt index 0892857a2df21..d6c967b59d346 100644 --- a/ext/openssl/tests/stream_security_level.phpt +++ b/ext/openssl/tests/stream_security_level.phpt @@ -19,7 +19,7 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_security_level.pem.tmp'; $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_security_level-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64322"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', @@ -29,14 +29,14 @@ $serverCode = <<<'CODE' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); CODE; $serverCode = sprintf($serverCode, $certFile); $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64322"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'security_level' => %d, @@ -45,7 +45,6 @@ $clientCode = <<<'CODE' 'verify_peer_name' => false ]]); - phpt_wait(); $client = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); var_dump($client); @@ -71,5 +70,5 @@ error:%s:SSL routines:%S:certificate verify failed in %s : eval()'d code on line Warning: stream_socket_client(): Failed to enable crypto in %s : eval()'d code on line %d -Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:64322 (Unknown error) in %s : eval()'d code on line %d +Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:%d (Unknown error) in %s : eval()'d code on line %d bool(false) diff --git a/ext/openssl/tests/stream_server_reneg_limit.phpt b/ext/openssl/tests/stream_server_reneg_limit.phpt index d661e9dc42331..d84906c81ca75 100644 --- a/ext/openssl/tests/stream_server_reneg_limit.phpt +++ b/ext/openssl/tests/stream_server_reneg_limit.phpt @@ -99,7 +99,7 @@ $certificateGenerator = new CertificateGenerator(); $certificateGenerator->saveNewCertAsFileWithKey('stream_security_level', $certFile); include 'ServerClientTestCase.inc'; -ServerClientTestCase::getInstance()->run($serverCode, $clientCode); +ServerClientTestCase::getInstance()->run($serverCode, $clientCode, false); ?> --CLEAN-- [ 'local_cert' => '%s' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); CODE; @@ -26,14 +26,13 @@ $serverCode = sprintf($serverCode, $certFile); $peerName = 'stream_verify_peer_name_001'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => false, 'peer_name' => '%s' ]]); - phpt_wait(); $client = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); var_dump($client); diff --git a/ext/openssl/tests/stream_verify_peer_name_002.phpt b/ext/openssl/tests/stream_verify_peer_name_002.phpt index a18ddd691114e..c6c4045a1a62c 100644 --- a/ext/openssl/tests/stream_verify_peer_name_002.phpt +++ b/ext/openssl/tests/stream_verify_peer_name_002.phpt @@ -12,14 +12,14 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_verify_peer_name_002.pem.tmp $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_verify_peer_name_002-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); CODE; @@ -27,7 +27,7 @@ $serverCode = sprintf($serverCode, $certFile); $actualPeerName = 'stream_verify_peer_name_002'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, @@ -35,7 +35,6 @@ $clientCode = <<<'CODE' 'verify_peer_name' => false ]]); - phpt_wait(); $client = stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx); var_dump($client); diff --git a/ext/openssl/tests/stream_verify_peer_name_003.phpt b/ext/openssl/tests/stream_verify_peer_name_003.phpt index 835e55eec0694..1ebd42c2fd455 100644 --- a/ext/openssl/tests/stream_verify_peer_name_003.phpt +++ b/ext/openssl/tests/stream_verify_peer_name_003.phpt @@ -12,14 +12,14 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_verify_peer_name_003.pem.tmp $cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_verify_peer_name_003-ca.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s' ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); @stream_socket_accept($server, 1); CODE; @@ -27,14 +27,13 @@ $serverCode = sprintf($serverCode, $certFile); $actualPeerName = 'stream_verify_peer_name_003'; $clientCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://{{ ADDR }}"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'verify_peer' => true, 'cafile' => '%s' ]]); - phpt_wait(); $client = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); var_dump($client); @@ -59,5 +58,5 @@ Warning: stream_socket_client(): Peer certificate CN=`stream_verify_peer_name_00 Warning: stream_socket_client(): Failed to enable crypto in %s on line %d -Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:%d (Unknown error) in %s on line %d bool(false) diff --git a/ext/openssl/tests/streams_crypto_method.phpt b/ext/openssl/tests/streams_crypto_method.phpt index 92654c877c5e3..39584b50cdbfa 100644 --- a/ext/openssl/tests/streams_crypto_method.phpt +++ b/ext/openssl/tests/streams_crypto_method.phpt @@ -11,14 +11,14 @@ if (!function_exists("proc_open")) die("skip no proc_open"); $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'streams_crypto_method.pem.tmp'; $serverCode = <<<'CODE' - $serverUri = "ssl://127.0.0.1:64321"; + $serverUri = "ssl://127.0.0.1:0"; $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', ]]); $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); - phpt_notify(); + phpt_notify_server_start($server); $client = @stream_socket_accept($server); if ($client) { @@ -39,7 +39,7 @@ CODE; $serverCode = sprintf($serverCode, $certFile); $clientCode = <<<'CODE' - $serverUri = "https://127.0.0.1:64321/"; + $serverUri = "https://{{ ADDR }}/"; $clientFlags = STREAM_CLIENT_CONNECT; $clientCtx = stream_context_create(['ssl' => [ 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, @@ -47,7 +47,6 @@ $clientCode = <<<'CODE' 'verify_peer_name' => false ]]); - phpt_wait(); echo file_get_contents($serverUri, false, $clientCtx); CODE; diff --git a/ext/openssl/tests/tls_min_v1.0_max_v1.1_wrapper.phpt b/ext/openssl/tests/tls_min_v1.0_max_v1.1_wrapper.phpt index 5d04263cfbc74..5be76547f209d 100644 --- a/ext/openssl/tests/tls_min_v1.0_max_v1.1_wrapper.phpt +++ b/ext/openssl/tests/tls_min_v1.0_max_v1.1_wrapper.phpt @@ -19,8 +19,8 @@ $serverCode = <<<'CODE' 'security_level' => 0, ]]); - $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); for ($i=0; $i < (phpt_has_sslv3() ? 6 : 5); $i++) { @stream_socket_accept($server, 3); @@ -36,24 +36,22 @@ $clientCode = <<<'CODE' 'security_level' => 0, ]]); - phpt_wait(); - - $client = stream_socket_client("tlsv1.0://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = stream_socket_client("tlsv1.0://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("sslv3://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.1://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.1://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.2://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("ssl://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); CODE; diff --git a/ext/openssl/tests/tls_wrapper.phpt b/ext/openssl/tests/tls_wrapper.phpt index 2220fbc0ac1da..7dcaa704cab89 100644 --- a/ext/openssl/tests/tls_wrapper.phpt +++ b/ext/openssl/tests/tls_wrapper.phpt @@ -18,8 +18,8 @@ $serverCode = <<<'CODE' 'security_level' => 0, ]]); - $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); for ($i = 0; $i < (phpt_has_sslv3() ? 6 : 5); $i++) { @stream_socket_accept($server, 3); @@ -35,24 +35,22 @@ $clientCode = <<<'CODE' 'security_level' => 0, ]]); - phpt_wait(); - - $client = stream_socket_client("tlsv1.0://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = stream_socket_client("tlsv1.0://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("sslv3://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.1://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.1://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.2://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("ssl://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); CODE; diff --git a/ext/openssl/tests/tls_wrapper_with_tls_v1.3.phpt b/ext/openssl/tests/tls_wrapper_with_tls_v1.3.phpt index 67c30cac87bcb..5d38c5606c4f0 100644 --- a/ext/openssl/tests/tls_wrapper_with_tls_v1.3.phpt +++ b/ext/openssl/tests/tls_wrapper_with_tls_v1.3.phpt @@ -18,8 +18,8 @@ $serverCode = <<<'CODE' 'security_level' => 0, ]]); - $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); for ($i = 0; $i < (phpt_has_sslv3() ? 7 : 6); $i++) { @stream_socket_accept($server, 3); @@ -35,27 +35,25 @@ $clientCode = <<<'CODE' 'security_level' => 0, ]]); - phpt_wait(); - - $client = stream_socket_client("tlsv1.0://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = stream_socket_client("tlsv1.0://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("sslv3://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.1://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.1://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.2://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.3://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("ssl://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); CODE; diff --git a/ext/openssl/tests/tlsv1.0_wrapper.phpt b/ext/openssl/tests/tlsv1.0_wrapper.phpt index c712217271b1e..38d44847cdb59 100644 --- a/ext/openssl/tests/tlsv1.0_wrapper.phpt +++ b/ext/openssl/tests/tlsv1.0_wrapper.phpt @@ -17,8 +17,8 @@ $serverCode = <<<'CODE' 'security_level' => 0, ]]); - $server = stream_socket_server('tlsv1.0://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tlsv1.0://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); for ($i = 0; $i < (phpt_has_sslv3() ? 3 : 2); $i++) { @stream_socket_accept($server, 3); @@ -34,15 +34,13 @@ $clientCode = <<<'CODE' 'security_level' => 0, ]]); - phpt_wait(); - - $client = stream_socket_client("tlsv1.0://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = stream_socket_client("tlsv1.0://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("sslv3://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.2://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); CODE; diff --git a/ext/openssl/tests/tlsv1.1_wrapper.phpt b/ext/openssl/tests/tlsv1.1_wrapper.phpt index a1525350572bb..6cdcd52fe500f 100644 --- a/ext/openssl/tests/tlsv1.1_wrapper.phpt +++ b/ext/openssl/tests/tlsv1.1_wrapper.phpt @@ -17,8 +17,8 @@ $serverCode = <<<'CODE' 'security_level' => 0, ]]); - $server = stream_socket_server('tlsv1.1://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tlsv1.1://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); for ($i = 0; $i < (phpt_has_sslv3() ? 3 : 2); $i++) { @stream_socket_accept($server, 3); @@ -34,15 +34,13 @@ $clientCode = <<<'CODE' 'security_level' => 0, ]]); - phpt_wait(); - - $client = stream_socket_client("tlsv1.1://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = stream_socket_client("tlsv1.1://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("sslv3://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.2://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); CODE; diff --git a/ext/openssl/tests/tlsv1.2_wrapper.phpt b/ext/openssl/tests/tlsv1.2_wrapper.phpt index b0b2c28c48379..e429687b52c46 100644 --- a/ext/openssl/tests/tlsv1.2_wrapper.phpt +++ b/ext/openssl/tests/tlsv1.2_wrapper.phpt @@ -16,8 +16,8 @@ $serverCode = <<<'CODE' 'local_cert' => '%s', ]]); - $server = stream_socket_server('tlsv1.2://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tlsv1.2://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); for ($i = 0; $i < (phpt_has_sslv3() ? 3 : 2); $i++) { @stream_socket_accept($server, 3); @@ -32,15 +32,13 @@ $clientCode = <<<'CODE' 'verify_peer_name' => false, ]]); - phpt_wait(); - - $client = stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = stream_socket_client("tlsv1.2://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("sslv3://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.1://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.1://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); CODE; diff --git a/ext/openssl/tests/tlsv1.3_wrapper.phpt b/ext/openssl/tests/tlsv1.3_wrapper.phpt index 9b04a2ef002ac..ee22a9e1c4bc8 100644 --- a/ext/openssl/tests/tlsv1.3_wrapper.phpt +++ b/ext/openssl/tests/tlsv1.3_wrapper.phpt @@ -17,8 +17,8 @@ $serverCode = <<<'CODE' 'local_cert' => '%s', ]]); - $server = stream_socket_server('tlsv1.3://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); - phpt_notify(); + $server = stream_socket_server('tlsv1.3://127.0.0.1:0', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); for ($i=0; $i < 3; $i++) { @stream_socket_accept($server, 3); @@ -33,15 +33,13 @@ $clientCode = <<<'CODE' 'verify_peer_name' => false, ]]); - phpt_wait(); - - $client = stream_socket_client("tlsv1.3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = stream_socket_client("tlsv1.3://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.0://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.0://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); - $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + $client = @stream_socket_client("tlsv1.2://{{ ADDR }}", $errno, $errstr, 3, $flags, $ctx); var_dump($client); CODE; diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 19460ad8b53fd..adb94af2fb463 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -540,7 +540,9 @@ PHP_FUNCTION(pcntl_exec) envs_hash = Z_ARRVAL_P(envs); envc = zend_hash_num_elements(envs_hash); - pair = envp = safe_emalloc((envc + 1), sizeof(char *), 0); + size_t envp_len = (envc + 1); + pair = envp = safe_emalloc(envp_len, sizeof(char *), 0); + memset(envp, 0, sizeof(char *) * envp_len); ZEND_HASH_FOREACH_KEY_VAL(envs_hash, key_num, key, element) { if (envi >= envc) break; if (!key) { @@ -551,9 +553,7 @@ PHP_FUNCTION(pcntl_exec) if (!try_convert_to_string(element)) { zend_string_release(key); - efree(argv); - efree(envp); - RETURN_THROWS(); + goto cleanup_env_vars; } /* Length of element + equal sign + length of key + null */ @@ -576,6 +576,7 @@ PHP_FUNCTION(pcntl_exec) php_error_docref(NULL, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno)); } +cleanup_env_vars: /* Cleanup */ for (pair = envp; *pair != NULL; pair++) efree(*pair); efree(envp); diff --git a/ext/pcntl/tests/pcntl_exec_invalid_strings.phpt b/ext/pcntl/tests/pcntl_exec_invalid_strings.phpt new file mode 100644 index 0000000000000..7b2b5e51b8faa --- /dev/null +++ b/ext/pcntl/tests/pcntl_exec_invalid_strings.phpt @@ -0,0 +1,25 @@ +--TEST-- +pcntl_exec(): Test cleanup after non-stringable array value has been encountered for $args and $env_vars. +--EXTENSIONS-- +pcntl +--FILE-- +getMessage(), "\n"; +} + +try { + pcntl_exec( + 'cmd', + ['-n'], + ['var1' => 'value1', 'var2' => new stdClass()], + ); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Error: Object of class stdClass could not be converted to string +Error: Object of class stdClass could not be converted to string diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 4087e61670230..e955eed0928c8 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -984,12 +984,15 @@ PHP_FUNCTION(pg_query) } link = FETCH_DEFAULT_LINK(); CHECK_DEFAULT_LINK(link); - } else { + } else if (ZEND_NUM_ARGS() == 2) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pgsql_link, pgsql_link_ce, &query, &query_len) == FAILURE) { RETURN_THROWS(); } link = Z_PGSQL_LINK_P(pgsql_link); CHECK_PGSQL_LINK(link); + } else { + zend_wrong_parameters_count_error(1, 2); + RETURN_THROWS(); } pgsql = link->conn; @@ -1078,12 +1081,15 @@ PHP_FUNCTION(pg_query_params) } link = FETCH_DEFAULT_LINK(); CHECK_DEFAULT_LINK(link); - } else { + } else if (ZEND_NUM_ARGS() == 3) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "Osa", &pgsql_link, pgsql_link_ce, &query, &query_len, &pv_param_arr) == FAILURE) { RETURN_THROWS(); } link = Z_PGSQL_LINK_P(pgsql_link); CHECK_PGSQL_LINK(link); + } else { + zend_wrong_parameters_count_error(2, 3); + RETURN_THROWS(); } pgsql = link->conn; @@ -1183,12 +1189,15 @@ PHP_FUNCTION(pg_prepare) } link = FETCH_DEFAULT_LINK(); CHECK_DEFAULT_LINK(link); - } else { + } else if (ZEND_NUM_ARGS() == 3) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oss", &pgsql_link, pgsql_link_ce, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) { RETURN_THROWS(); } link = Z_PGSQL_LINK_P(pgsql_link); CHECK_PGSQL_LINK(link); + } else { + zend_wrong_parameters_count_error(2, 3); + RETURN_THROWS(); } pgsql = link->conn; @@ -1264,12 +1273,15 @@ PHP_FUNCTION(pg_execute) } link = FETCH_DEFAULT_LINK(); CHECK_DEFAULT_LINK(link); - } else { + } else if (ZEND_NUM_ARGS() == 3) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "Osa", &pgsql_link, pgsql_link_ce, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) { RETURN_THROWS(); } link = Z_PGSQL_LINK_P(pgsql_link); CHECK_PGSQL_LINK(link); + } else { + zend_wrong_parameters_count_error(2, 3); + RETURN_THROWS(); } pgsql = link->conn; @@ -1710,7 +1722,7 @@ PHP_FUNCTION(pg_fetch_result) Z_PARAM_OBJECT_OF_CLASS(result, pgsql_result_ce) Z_PARAM_STR_OR_LONG(field_name, field_offset) ZEND_PARSE_PARAMETERS_END(); - } else { + } else if (ZEND_NUM_ARGS() == 3) { ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_OBJECT_OF_CLASS(result, pgsql_result_ce) if (zend_string_equals_literal(EG(current_execute_data)->func->common.function_name, "pg_result")) { @@ -1720,6 +1732,9 @@ PHP_FUNCTION(pg_fetch_result) } Z_PARAM_STR_OR_LONG(field_name, field_offset) ZEND_PARSE_PARAMETERS_END(); + } else { + zend_wrong_parameters_count_error(2, 3); + RETURN_THROWS(); } pg_result = Z_PGSQL_RESULT_P(result); @@ -2021,7 +2036,7 @@ static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type, bo Z_PARAM_OBJECT_OF_CLASS(result, pgsql_result_ce) Z_PARAM_STR_OR_LONG(field_name, field_offset) ZEND_PARSE_PARAMETERS_END(); - } else { + } else if (ZEND_NUM_ARGS() == 3) { ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_OBJECT_OF_CLASS(result, pgsql_result_ce) if (nullable_row) { @@ -2031,6 +2046,9 @@ static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type, bo } Z_PARAM_STR_OR_LONG(field_name, field_offset) ZEND_PARSE_PARAMETERS_END(); + } else { + zend_wrong_parameters_count_error(2, 3); + RETURN_THROWS(); } pg_result = Z_PGSQL_RESULT_P(result); @@ -2846,12 +2864,15 @@ PHP_FUNCTION(pg_set_error_verbosity) } link = FETCH_DEFAULT_LINK(); CHECK_DEFAULT_LINK(link); - } else { + } else if (ZEND_NUM_ARGS() == 2) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pgsql_link, pgsql_link_ce, &verbosity) == FAILURE) { RETURN_THROWS(); } link = Z_PGSQL_LINK_P(pgsql_link); CHECK_PGSQL_LINK(link); + } else { + zend_wrong_parameters_count_error(1, 2); + RETURN_THROWS(); } pgsql = link->conn; @@ -2904,12 +2925,15 @@ PHP_FUNCTION(pg_set_client_encoding) } link = FETCH_DEFAULT_LINK(); CHECK_DEFAULT_LINK(link); - } else { + } else if (ZEND_NUM_ARGS() == 2) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pgsql_link, pgsql_link_ce, &encoding, &encoding_len) == FAILURE) { RETURN_THROWS(); } link = Z_PGSQL_LINK_P(pgsql_link); CHECK_PGSQL_LINK(link); + } else { + zend_wrong_parameters_count_error(1, 2); + RETURN_THROWS(); } pgsql = link->conn; @@ -2993,12 +3017,15 @@ PHP_FUNCTION(pg_put_line) } link = FETCH_DEFAULT_LINK(); CHECK_DEFAULT_LINK(link); - } else { + } else if (ZEND_NUM_ARGS() == 2) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pgsql_link, pgsql_link_ce, &query, &query_len) == FAILURE) { RETURN_THROWS(); } link = Z_PGSQL_LINK_P(pgsql_link); CHECK_PGSQL_LINK(link); + } else { + zend_wrong_parameters_count_error(1, 2); + RETURN_THROWS(); } pgsql = link->conn; diff --git a/ext/pgsql/tests/gh17158.phpt b/ext/pgsql/tests/gh17158.phpt new file mode 100644 index 0000000000000..ade47ededed12 --- /dev/null +++ b/ext/pgsql/tests/gh17158.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-17158 (pg_fetch_result Shows Incorrect ArgumentCountError Message when Called With 1 Argument) +--EXTENSIONS-- +pgsql +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +pg_fetch_result() expects at least 2 arguments, 1 given diff --git a/ext/pgsql/tests/gh17165.phpt b/ext/pgsql/tests/gh17165.phpt new file mode 100644 index 0000000000000..2fe3f2ad18add --- /dev/null +++ b/ext/pgsql/tests/gh17165.phpt @@ -0,0 +1,65 @@ +--TEST-- +Fix pg_query()/pg_query_params()/pg_prepare()/pg_execute()/pg_set_error_verbosity()/pg_set_client_encoding()/pg_put_line() pg field infos calls ArgumentCountError message. +--EXTENSIONS-- +pgsql +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +try { + pg_query_params($db, "b", array(), "d"); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + pg_prepare($db, "a", "b", "c"); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + pg_set_error_verbosity($db, 0, PHP_INT_MAX); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + pg_set_client_encoding($db, "foo", "bar"); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + pg_put_line($db, "my", "data"); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + pg_field_is_null($db, false, "myfield", new stdClass()); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), PHP_EOL; +} +?> +--EXPECT-- +pg_query() expects at most 2 arguments, 3 given +pg_query_params() expects at most 3 arguments, 4 given +pg_prepare() expects at most 3 arguments, 4 given +pg_set_error_verbosity() expects at most 2 arguments, 3 given +pg_set_client_encoding() expects at most 2 arguments, 3 given +pg_put_line() expects at most 2 arguments, 3 given +pg_field_is_null() expects at most 3 arguments, 4 given diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 6f52fc714d6b7..dfdbbb8fb8390 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -1504,6 +1504,7 @@ int phar_create_or_parse_filename(char *fname, size_t fname_len, char *alias, si } } + ZEND_ASSERT(!mydata->is_persistent); mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len); mydata->alias_len = alias ? alias_len : fname_len; } diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 470e1e8a993be..98efcf701c6c4 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -2112,9 +2112,8 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /* efree(newname); if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, newpath, phar->fname_len))) { - efree(oldpath); zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to add newly converted phar \"%s\" to the list of phars, new phar name is in phar.cache_list", phar->fname); - return NULL; + goto err_oldpath; } if (NULL != (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), newpath, phar->fname_len))) { @@ -2126,41 +2125,42 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /* pphar->flags = phar->flags; pphar->fp = phar->fp; phar->fp = NULL; - /* FIX: GH-10755 Double-free issue caught by ASAN check */ - pphar->alias = phar->alias; /* Transfer alias to pphar to */ - phar->alias = NULL; /* avoid being free'd twice */ + /* The alias is not owned by the phar, so set it to NULL to avoid freeing it. */ + phar->alias = NULL; phar_destroy_phar_data(phar); *sphar = NULL; phar = pphar; + /* NOTE: this phar is now reused, so the refcount must be increased. */ + phar->refcount++; newpath = oldpath; goto its_ok; } } - efree(oldpath); zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to add newly converted phar \"%s\" to the list of phars, a phar with that name already exists", phar->fname); - return NULL; + goto err_oldpath; } its_ok: if (SUCCESS == php_stream_stat_path(newpath, &ssb)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "phar \"%s\" exists and must be unlinked prior to conversion", newpath); - efree(oldpath); - return NULL; + goto err_reused_oldpath; } if (!phar->is_data) { if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &ext_len, 1, 1, 1)) { - efree(oldpath); zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "phar \"%s\" has invalid extension %s", phar->fname, ext); - return NULL; + goto err_reused_oldpath; } phar->ext_len = ext_len; - if (phar->alias) { + /* If we are reusing a phar, then the aliases should be already set up correctly, + * and so we should not clear out the alias information. + * This would also leak memory because, unlike the non-reuse path, we actually own the alias memory. */ + if (phar->alias && phar != pphar) { if (phar->is_temporary_alias) { phar->alias = NULL; phar->alias_len = 0; } else { - phar->alias = estrndup(newpath, strlen(newpath)); + phar->alias = pestrndup(newpath, strlen(newpath), phar->is_persistent); phar->alias_len = strlen(newpath); phar->is_temporary_alias = 1; zend_hash_str_update_ptr(&(PHAR_G(phar_alias_map)), newpath, phar->fname_len, phar); @@ -2170,20 +2170,21 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /* } else { if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &ext_len, 0, 1, 1)) { - efree(oldpath); zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "data phar \"%s\" has invalid extension %s", phar->fname, ext); - return NULL; + goto err_reused_oldpath; } phar->ext_len = ext_len; - phar->alias = NULL; - phar->alias_len = 0; + /* See comment in other branch. */ + if (phar != pphar) { + phar->alias = NULL; + phar->alias_len = 0; + } } if ((!pphar || phar == pphar) && NULL == zend_hash_str_update_ptr(&(PHAR_G(phar_fname_map)), newpath, phar->fname_len, phar)) { - efree(oldpath); zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to add newly converted phar \"%s\" to the list of phars", phar->fname); - return NULL; + goto err_oldpath; } phar_flush(phar, 0, 0, 1, &error); @@ -2193,8 +2194,7 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /* *sphar = NULL; zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s", error); efree(error); - efree(oldpath); - return NULL; + goto err_oldpath; } efree(oldpath); @@ -2217,6 +2217,16 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /* zend_call_known_instance_method_with_1_params(ce->constructor, Z_OBJ(ret), NULL, &arg1); zval_ptr_dtor(&arg1); return Z_OBJ(ret); + +err_reused_oldpath: + if (pphar == phar) { + /* NOTE: we know it's not the last reference because the phar is reused. */ + phar->refcount--; + } + /* fallthrough */ +err_oldpath: + efree(oldpath); + return NULL; } /* }}} */ @@ -2747,7 +2757,7 @@ PHP_METHOD(Phar, setAlias) old_temp = phar_obj->archive->is_temporary_alias; if (alias_len) { - phar_obj->archive->alias = estrndup(alias, alias_len); + phar_obj->archive->alias = pestrndup(alias, alias_len, phar_obj->archive->is_persistent); } else { phar_obj->archive->alias = NULL; } diff --git a/ext/phar/tests/gh17137.phpt b/ext/phar/tests/gh17137.phpt new file mode 100644 index 0000000000000..b96036420e931 --- /dev/null +++ b/ext/phar/tests/gh17137.phpt @@ -0,0 +1,31 @@ +--TEST-- +GH-17137 (Segmentation fault ext/phar/phar.c) +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +--FILE-- +decompress()); +echo "OK\n"; +?> +--EXPECTF-- +object(Phar)#%d (3) { + ["pathName":"SplFileInfo":private]=> + string(0) "" + ["glob":"DirectoryIterator":private]=> + bool(false) + ["subPathName":"RecursiveDirectoryIterator":private]=> + string(0) "" +} +object(Phar)#%d (3) { + ["pathName":"SplFileInfo":private]=> + string(0) "" + ["glob":"DirectoryIterator":private]=> + bool(false) + ["subPathName":"RecursiveDirectoryIterator":private]=> + string(0) "" +} +OK diff --git a/ext/posix/posix.c b/ext/posix/posix.c index ecbb849408723..2c87fbd28d981 100644 --- a/ext/posix/posix.c +++ b/ext/posix/posix.c @@ -23,6 +23,7 @@ #include "ext/standard/info.h" #include "ext/standard/php_string.h" #include "php_posix.h" +#include "main/php_network.h" #ifdef HAVE_POSIX @@ -417,7 +418,7 @@ PHP_FUNCTION(posix_ctermid) /* }}} */ /* Checks if the provides resource is a stream and if it provides a file descriptor */ -static int php_posix_stream_get_fd(zval *zfp, zend_long *fd) /* {{{ */ +static int php_posix_stream_get_fd(zval *zfp, zend_long *ret) /* {{{ */ { php_stream *stream; @@ -427,19 +428,21 @@ static int php_posix_stream_get_fd(zval *zfp, zend_long *fd) /* {{{ */ return 0; } - /* get the fd. + /* get the fd. php_socket_t is used for FDs, and is shorter than zend_long. * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag when casting. * It is only used here so that the buffered data warning is not displayed. */ + php_socket_t fd = -1; if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL) == SUCCESS) { - php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)fd, 0); + php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void**)&fd, 0); } else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL) == SUCCESS) { - php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void*)fd, 0); + php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void**)&fd, 0); } else { php_error_docref(NULL, E_WARNING, "Could not use stream of type '%s'", stream->ops->label); return 0; } + *ret = fd; return 1; } /* }}} */ diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 6a5a514f9a3d3..00551267a45e9 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -54,6 +54,16 @@ static void php_sxe_iterator_move_forward(zend_object_iterator *iter); static void php_sxe_iterator_rewind(zend_object_iterator *iter); static zend_result sxe_object_cast_ex(zend_object *readobj, zval *writeobj, int type); +static void sxe_unlink_node(xmlNodePtr node) +{ + xmlUnlinkNode(node); + /* Only destroy the nodes if we have no objects using them anymore. + * Don't assume simplexml owns these. */ + if (!node->_private) { + php_libxml_node_free_resource(node); + } +} + /* {{{ _node_as_zval() */ static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, SXE_ITER itertype, char *name, const xmlChar *nsprefix, int isprefix) { @@ -554,8 +564,7 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, } if (value_str) { while ((tempnode = (xmlNodePtr) newnode->children)) { - xmlUnlinkNode(tempnode); - php_libxml_node_free_resource((xmlNodePtr) tempnode); + sxe_unlink_node(tempnode); } change_node_zval(newnode, value_str); } @@ -567,7 +576,10 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, if (!member || Z_TYPE_P(member) == IS_LONG) { newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value_str ? (xmlChar *)ZSTR_VAL(value_str) : NULL); } else { - newnode = xmlNewTextChild(mynode, mynode->ns, (xmlChar *)Z_STRVAL_P(member), value_str ? (xmlChar *)ZSTR_VAL(value_str) : NULL); + /* Note: we cannot set the namespace here unconditionally because the parent may be a document. + * Passing NULL will let libxml decide to either inherit the namespace or not set one at all, + * depending on whether the parent is an element. */ + newnode = xmlNewTextChild(mynode, NULL, (xmlChar *)Z_STRVAL_P(member), value_str ? (xmlChar *)ZSTR_VAL(value_str) : NULL); } } else if (!member || Z_TYPE_P(member) == IS_LONG) { if (member && cnt < Z_LVAL_P(member)) { @@ -829,8 +841,7 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements while (attr && nodendx <= Z_LVAL_P(member)) { if ((!test || xmlStrEqual(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { if (nodendx == Z_LVAL_P(member)) { - xmlUnlinkNode((xmlNodePtr) attr); - php_libxml_node_free_resource((xmlNodePtr) attr); + sxe_unlink_node((xmlNodePtr) attr); break; } nodendx++; @@ -841,8 +852,7 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements while (attr) { anext = attr->next; if ((!test || xmlStrEqual(attr->name, sxe->iter.name)) && xmlStrEqual(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { - xmlUnlinkNode((xmlNodePtr) attr); - php_libxml_node_free_resource((xmlNodePtr) attr); + sxe_unlink_node((xmlNodePtr) attr); break; } attr = anext; @@ -857,8 +867,7 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements } node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL); if (node) { - xmlUnlinkNode(node); - php_libxml_node_free_resource(node); + sxe_unlink_node(node); } } else { node = node->children; @@ -868,8 +877,7 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements SKIP_TEXT(node); if (xmlStrEqual(node->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) { - xmlUnlinkNode(node); - php_libxml_node_free_resource(node); + sxe_unlink_node(node); } next_iter: diff --git a/ext/simplexml/tests/gh17040.phpt b/ext/simplexml/tests/gh17040.phpt new file mode 100644 index 0000000000000..20dc9062d559b --- /dev/null +++ b/ext/simplexml/tests/gh17040.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-17040 (SimpleXML's unset can break DOM objects) +--EXTENSIONS-- +dom +simplexml +--FILE-- +appendChild($dom->createElement("style")); +$html = simplexml_import_dom($tag); +unset($html[0]); +$tag->append("foo"); +echo $dom->saveXML(), "\n"; +echo $dom->saveXML($tag), "\n"; +var_dump($html); +?> +--EXPECT-- + + + +object(SimpleXMLElement)#3 (1) { + [0]=> + string(3) "foo" +} diff --git a/ext/simplexml/tests/gh17153.phpt b/ext/simplexml/tests/gh17153.phpt new file mode 100644 index 0000000000000..0958f613bb74c --- /dev/null +++ b/ext/simplexml/tests/gh17153.phpt @@ -0,0 +1,45 @@ +--TEST-- +GH-17153 (SimpleXML crash when using autovivification on document) +--EXTENSIONS-- +dom +simplexml +xsl +--FILE-- +load(__DIR__ . '/../../xsl/tests/53965/collection.xsl'); +$processor->importStylesheet($dom); +$result = $processor->transformToDoc($sxe, SimpleXMLElement::class); +$result->h = "x"; +var_dump($result); +?> +--EXPECT-- +object(SimpleXMLElement)#4 (4) { + ["h1"]=> + array(2) { + [0]=> + string(19) "Fight for your mind" + [1]=> + string(17) "Electric Ladyland" + } + ["h2"]=> + array(2) { + [0]=> + string(20) "by Ben Harper - 1995" + [1]=> + string(22) "by Jimi Hendrix - 1997" + } + ["hr"]=> + array(2) { + [0]=> + object(SimpleXMLElement)#5 (0) { + } + [1]=> + object(SimpleXMLElement)#6 (0) { + } + } + ["h"]=> + string(1) "x" +} diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 2f731b3b05acc..e6e231e2e5e7e 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -354,7 +354,11 @@ char *sockets_strerror(int error) /* {{{ */ #ifndef PHP_WIN32 if (error < -10000) { - error = -error - 10000; + if (error == INT_MIN) { + error = 2147473648; + } else { + error = -error - 10000; + } #ifdef HAVE_HSTRERROR buf = hstrerror(error); @@ -1867,8 +1871,16 @@ PHP_FUNCTION(socket_set_option) const char l_onoff_key[] = "l_onoff"; const char l_linger_key[] = "l_linger"; - convert_to_array(arg4); - opt_ht = Z_ARRVAL_P(arg4); + if (Z_TYPE_P(arg4) != IS_ARRAY) { + if (UNEXPECTED(Z_TYPE_P(arg4) != IS_OBJECT)) { + zend_argument_type_error(4, "must be of type array when argument #3 ($option) is SO_LINGER, %s given", zend_zval_value_name(arg4)); + RETURN_THROWS(); + } else { + opt_ht = Z_OBJPROP_P(arg4); + } + } else { + opt_ht = Z_ARRVAL_P(arg4); + } if ((l_onoff = zend_hash_str_find(opt_ht, l_onoff_key, sizeof(l_onoff_key) - 1)) == NULL) { zend_argument_value_error(4, "must have key \"%s\"", l_onoff_key); @@ -1879,11 +1891,21 @@ PHP_FUNCTION(socket_set_option) RETURN_THROWS(); } - convert_to_long(l_onoff); - convert_to_long(l_linger); + zend_long val_lonoff = zval_get_long(l_onoff); + zend_long val_linger = zval_get_long(l_linger); + + if (val_lonoff < 0 || val_lonoff > USHRT_MAX) { + zend_argument_value_error(4, "\"%s\" must be between 0 and %u", l_onoff_key, USHRT_MAX); + RETURN_THROWS(); + } + + if (val_linger < 0 || val_linger > USHRT_MAX) { + zend_argument_value_error(4, "\"%s\" must be between 0 and %d", l_linger, USHRT_MAX); + RETURN_THROWS(); + } - lv.l_onoff = (unsigned short)Z_LVAL_P(l_onoff); - lv.l_linger = (unsigned short)Z_LVAL_P(l_linger); + lv.l_onoff = (unsigned short)val_lonoff; + lv.l_linger = (unsigned short)val_linger; optlen = sizeof(lv); opt_ptr = &lv; @@ -1895,8 +1917,18 @@ PHP_FUNCTION(socket_set_option) const char sec_key[] = "sec"; const char usec_key[] = "usec"; - convert_to_array(arg4); - opt_ht = Z_ARRVAL_P(arg4); + if (Z_TYPE_P(arg4) != IS_ARRAY) { + if (UNEXPECTED(Z_TYPE_P(arg4) != IS_OBJECT)) { + zend_argument_type_error(4, "must be of type array when argument #3 ($option) is %s, %s given", + optname == SO_RCVTIMEO ? "SO_RCVTIMEO" : "SO_SNDTIMEO", + zend_zval_value_name(arg4)); + RETURN_THROWS(); + } else { + opt_ht = Z_OBJPROP_P(arg4); + } + } else { + opt_ht = Z_ARRVAL_P(arg4); + } if ((sec = zend_hash_str_find(opt_ht, sec_key, sizeof(sec_key) - 1)) == NULL) { zend_argument_value_error(4, "must have key \"%s\"", sec_key); @@ -1907,15 +1939,16 @@ PHP_FUNCTION(socket_set_option) RETURN_THROWS(); } - convert_to_long(sec); - convert_to_long(usec); + zend_long valsec = zval_get_long(sec); + zend_long valusec = zval_get_long(usec); #ifndef PHP_WIN32 - tv.tv_sec = Z_LVAL_P(sec); - tv.tv_usec = Z_LVAL_P(usec); + tv.tv_sec = valsec; + tv.tv_usec = valusec; optlen = sizeof(tv); opt_ptr = &tv; #else - timeout = Z_LVAL_P(sec) * 1000 + Z_LVAL_P(usec) / 1000; + timeout = valsec * 1000 + valusec / 1000; + optlen = sizeof(int); opt_ptr = &timeout; #endif @@ -1967,15 +2000,15 @@ PHP_FUNCTION(socket_set_option) #ifdef SO_ATTACH_REUSEPORT_CBPF case SO_ATTACH_REUSEPORT_CBPF: { - convert_to_long(arg4); + zend_long cbpf_val = zval_get_long(arg4); - if (!Z_LVAL_P(arg4)) { + if (!cbpf_val) { ov = 1; optlen = sizeof(ov); opt_ptr = &ov; optname = SO_DETACH_BPF; } else { - uint32_t k = (uint32_t)Z_LVAL_P(arg4); + uint32_t k = (uint32_t)cbpf_val; static struct sock_filter cbpf[8] = {0}; static struct sock_fprog bpfprog; @@ -2002,8 +2035,7 @@ PHP_FUNCTION(socket_set_option) default: default_case: - convert_to_long(arg4); - ov = Z_LVAL_P(arg4); + ov = zval_get_long(arg4); optlen = sizeof(ov); opt_ptr = &ov; diff --git a/ext/sockets/tests/gh16267.phpt b/ext/sockets/tests/gh16267.phpt index d2462b3164530..de3e1b657fbc5 100644 --- a/ext/sockets/tests/gh16267.phpt +++ b/ext/sockets/tests/gh16267.phpt @@ -3,20 +3,16 @@ GH-16267 - overflow on socket_strerror argument --EXTENSIONS-- sockets --SKIPIF-- - + --FILE-- getMessage() . PHP_EOL; -} -try { - socket_strerror(PHP_INT_MAX); + socket_strerror(2147483648); } catch (\ValueError $e) { echo $e->getMessage() . PHP_EOL; } ?> --EXPECTF-- -socket_strerror(): Argument #1 ($error_code) must be between %s and %s -socket_strerror(): Argument #1 ($error_code) must be between %s and %s +string(%d) "%S" +socket_strerror(): Argument #1 ($error_code) must be between %i and %d diff --git a/ext/sockets/tests/socket_reuseport_cbpf.phpt b/ext/sockets/tests/socket_reuseport_cbpf.phpt index 1d4824dca1c81..2210c4438f000 100644 --- a/ext/sockets/tests/socket_reuseport_cbpf.phpt +++ b/ext/sockets/tests/socket_reuseport_cbpf.phpt @@ -18,13 +18,20 @@ if (!$socket) { } var_dump(socket_set_option( $socket, SOL_SOCKET, SO_REUSEADDR, true)); var_dump(socket_set_option( $socket, SOL_SOCKET, SO_REUSEPORT, true)); +try { + socket_set_option( $socket, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, array()); +} catch (\TypeError $e) { + echo $e->getMessage() . PHP_EOL; +} var_dump(socket_set_option( $socket, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, SKF_AD_CPU)); var_dump(socket_bind($socket, '0.0.0.0')); socket_listen($socket); socket_close($socket); ?> ---EXPECT-- +--EXPECTF-- bool(true) bool(true) + +Warning: socket_set_option(): Unable to set socket option [2]: No such file or directory in %s on line %d bool(true) bool(true) diff --git a/ext/sockets/tests/socket_set_option_timeo_error.phpt b/ext/sockets/tests/socket_set_option_timeo_error.phpt new file mode 100644 index 0000000000000..1db5e01c36228 --- /dev/null +++ b/ext/sockets/tests/socket_set_option_timeo_error.phpt @@ -0,0 +1,66 @@ +--TEST-- +socket_set_option() with SO_RCVTIMEO/SO_SNDTIMEO/SO_LINGER +--EXTENSIONS-- +sockets +--FILE-- + 1, "usec" => "aaaaa"); +$options_2 = array("sec" => new stdClass(), "usec" => "1"); +$options_3 = array("l_onoff" => "aaaa", "l_linger" => "1"); +$options_4 = array("l_onoff" => "1", "l_linger" => []); +$options_5 = array("l_onoff" => PHP_INT_MAX, "l_linger" => "1"); + +try { + socket_set_option( $socket, SOL_SOCKET, SO_RCVTIMEO, new stdClass); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +try { + socket_set_option( $socket, SOL_SOCKET, SO_RCVTIMEO, $options_1); +} catch (\TypeError $e) { + echo $e->getMessage() . PHP_EOL; +} + +try { + socket_set_option( $socket, SOL_SOCKET, SO_SNDTIMEO, $options_2); +} catch (\TypeError $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + socket_set_option( $socket, SOL_SOCKET, SO_RCVTIMEO, "not good"); +} catch (\TypeError $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + socket_set_option( $socket, SOL_SOCKET, SO_LINGER, "not good neither"); +} catch (\TypeError $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + socket_set_option( $socket, SOL_SOCKET, SO_LINGER, $options_3); +} catch (\TypeError $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + socket_set_option( $socket, SOL_SOCKET, SO_LINGER, $options_4); +} catch (\TypeError $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + socket_set_option( $socket, SOL_SOCKET, SO_LINGER, $options_5); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +?> +--EXPECTF-- +socket_set_option(): Argument #4 ($value) must have key "sec" + +Warning: Object of class stdClass could not be converted to int in %s on line %d +socket_set_option(): Argument #4 ($value) must be of type array when argument #3 ($option) is SO_RCVTIMEO, string given +socket_set_option(): Argument #4 ($value) must be of type array when argument #3 ($option) is SO_LINGER, string given +socket_set_option(): Argument #4 ($value) "l_onoff" must be between 0 and %d diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 650439dbc8939..e4e79b0edb861 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -212,10 +212,16 @@ static zend_object *spl_filesystem_object_new(zend_class_entry *class_type) } /* }}} */ +static inline bool spl_intern_is_glob(const spl_filesystem_object *intern) +{ + /* NULL check on `dirp` is necessary as destructors may interfere. */ + return intern->u.dir.dirp && php_stream_is(intern->u.dir.dirp, &php_glob_stream_ops); +} + PHPAPI zend_string *spl_filesystem_object_get_path(spl_filesystem_object *intern) /* {{{ */ { #ifdef HAVE_GLOB - if (intern->type == SPL_FS_DIR && php_stream_is(intern->u.dir.dirp, &php_glob_stream_ops)) { + if (intern->type == SPL_FS_DIR && spl_intern_is_glob(intern)) { size_t len = 0; char *tmp = php_glob_stream_get_path(intern->u.dir.dirp, &len); if (len == 0) { @@ -658,7 +664,7 @@ static inline HashTable *spl_filesystem_object_get_debug_info(zend_object *objec if (intern->type == SPL_FS_DIR) { #ifdef HAVE_GLOB pnstr = spl_gen_private_prop_name(spl_ce_DirectoryIterator, "glob", sizeof("glob")-1); - if (intern->u.dir.dirp && php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) { + if (spl_intern_is_glob(intern)) { ZVAL_STR_COPY(&tmp, intern->path); } else { ZVAL_FALSE(&tmp); @@ -1614,11 +1620,11 @@ PHP_METHOD(GlobIterator, count) RETURN_THROWS(); } - if (intern->u.dir.dirp && php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) { + if (spl_intern_is_glob(intern)) { RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL)); } else { - /* should not happen */ - // TODO ZEND_ASSERT ? + /* This can happen by abusing destructors. */ + /* TODO: relax this from E_ERROR to an exception */ php_error_docref(NULL, E_ERROR, "GlobIterator lost glob state"); } } diff --git a/ext/spl/tests/gh17225.phpt b/ext/spl/tests/gh17225.phpt new file mode 100644 index 0000000000000..66a52bce7f4a7 --- /dev/null +++ b/ext/spl/tests/gh17225.phpt @@ -0,0 +1,52 @@ +--TEST-- +GH-17225 (NULL deref in spl_directory.c) +--CREDITS-- +YuanchengJiang +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +--FILE-- +isLink()); +?> +--CLEAN-- + +--EXPECTF-- +bool(false) +object(SplObjectStorage)#%d (1) { + ["storage":"SplObjectStorage":private]=> + array(1) { + [0]=> + array(2) { + ["obj"]=> + object(Phar)#%d (4) { + ["pathName":"SplFileInfo":private]=> + string(0) "" + ["fileName":"SplFileInfo":private]=> + string(0) "" + ["glob":"DirectoryIterator":private]=> + bool(false) + ["subPathName":"RecursiveDirectoryIterator":private]=> + string(0) "" + } + ["inf"]=> + object(HasDestructor)#%d (0) { + } + } + } +} diff --git a/ext/standard/Makefile.frag.w32 b/ext/standard/Makefile.frag.w32 index 7815c7c97d035..f4655cfa8bb27 100644 --- a/ext/standard/Makefile.frag.w32 +++ b/ext/standard/Makefile.frag.w32 @@ -7,3 +7,7 @@ ext\standard\url_scanner_ex.c: ext\standard\url_scanner_ex.re $(RE2C) $(RE2C_FLAGS) --no-generation-date -b -o ext/standard/url_scanner_ex.c ext/standard/url_scanner_ex.re $(BUILD_DIR)\ext\standard\basic_functions.obj: $(PHP_SRC_DIR)\Zend\zend_language_parser.h + +$(PHP_SRC_DIR)\ext\standard\tests\helpers\bad_cmd.exe: $(PHP_SRC_DIR)\ext\standard\tests\helpers\bad_cmd.c + cd $(PHP_SRC_DIR)\ext\standard\tests\helpers + $(PHP_CL) /nologo bad_cmd.c diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index bbc8acc73b9a6..fb987c82e5cc2 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -216,6 +216,18 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (context && (tmpzval = php_stream_context_get_option(context, wrapper->wops->label, "timeout")) != NULL) { double d = zval_get_double(tmpzval); +#ifndef PHP_WIN32 + const double timeoutmax = (double) PHP_TIMEOUT_ULL_MAX / 1000000.0; +#else + const double timeoutmax = (double) LONG_MAX / 1000000.0; +#endif + + if (d > timeoutmax) { + php_stream_wrapper_log_error(wrapper, options, "timeout must be lower than " ZEND_ULONG_FMT, (zend_ulong)timeoutmax); + zend_string_release(transport_string); + php_url_free(resource); + return NULL; + } #ifndef PHP_WIN32 timeout.tv_sec = (time_t) d; timeout.tv_usec = (size_t) ((d - timeout.tv_sec) * 1000000); diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 2d4cb42b7a661..ce77109827740 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -701,22 +701,77 @@ static void init_process_info(PROCESS_INFORMATION *pi) memset(&pi, 0, sizeof(pi)); } +/* on success, returns length of *comspec, which then needs to be efree'd by caller */ +static size_t find_comspec_nt(wchar_t **comspec) +{ + zend_string *path = NULL; + wchar_t *pathw = NULL; + wchar_t *bufp = NULL; + DWORD buflen = MAX_PATH, len = 0; + + path = php_getenv("PATH", 4); + if (path == NULL) { + goto out; + } + pathw = php_win32_cp_any_to_w(ZSTR_VAL(path)); + if (pathw == NULL) { + goto out; + } + bufp = emalloc(buflen * sizeof(wchar_t)); + do { + /* the first call to SearchPathW() fails if the buffer is too small, + * what is unlikely but possible; to avoid an explicit second call to + * SeachPathW() and the error handling, we're looping */ + len = SearchPathW(pathw, L"cmd.exe", NULL, buflen, bufp, NULL); + if (len == 0) { + goto out; + } + if (len < buflen) { + break; + } + buflen = len; + bufp = erealloc(bufp, buflen * sizeof(wchar_t)); + } while (1); + *comspec = bufp; + +out: + if (path != NULL) { + zend_string_release(path); + } + if (pathw != NULL) { + free(pathw); + } + if (bufp != NULL && bufp != *comspec) { + efree(bufp); + } + return len; +} + static zend_result convert_command_to_use_shell(wchar_t **cmdw, size_t cmdw_len) { - size_t len = sizeof(COMSPEC_NT) + sizeof(" /s /c ") + cmdw_len + 3; + wchar_t *comspec; + size_t len = find_comspec_nt(&comspec); + if (len == 0) { + php_error_docref(NULL, E_WARNING, "Command conversion failed"); + return FAILURE; + } + len += sizeof(" /s /c ") + cmdw_len + 3; wchar_t *cmdw_shell = (wchar_t *)malloc(len * sizeof(wchar_t)); if (cmdw_shell == NULL) { + efree(comspec); php_error_docref(NULL, E_WARNING, "Command conversion failed"); return FAILURE; } - if (_snwprintf(cmdw_shell, len, L"%hs /s /c \"%s\"", COMSPEC_NT, *cmdw) == -1) { + if (_snwprintf(cmdw_shell, len, L"%s /s /c \"%s\"", comspec, *cmdw) == -1) { + efree(comspec); free(cmdw_shell); php_error_docref(NULL, E_WARNING, "Command conversion failed"); return FAILURE; } + efree(comspec); free(*cmdw); *cmdw = cmdw_shell; diff --git a/ext/standard/tests/file/parse_ini_file_variation6.phpt b/ext/standard/tests/file/parse_ini_file_variation6.phpt index 70e1a73f988e7..4c84672821d8f 100644 --- a/ext/standard/tests/file/parse_ini_file_variation6.phpt +++ b/ext/standard/tests/file/parse_ini_file_variation6.phpt @@ -2,6 +2,10 @@ Test parse_ini_file() function : variation - various absolute and relative paths --CREDITS-- Dave Kelsey +--SKIPIF-- + --FILE-- +--EXPECT-- +bool(false) diff --git a/ext/standard/tests/general_functions/gh17211.phpt b/ext/standard/tests/general_functions/gh17211.phpt new file mode 100644 index 0000000000000..5df8a6638a677 --- /dev/null +++ b/ext/standard/tests/general_functions/gh17211.phpt @@ -0,0 +1,42 @@ +--TEST-- +dl() / observer segfault +--EXTENSIONS-- +zend_test +--SKIPIF-- + +--INI-- +zend_test.observer.enabled=1 +zend_test.observer.observe_functions=1 +zend_test.observer.show_output=1 +--FILE-- +test("World!")); +?> +--EXPECTF-- + + +
+
+ + + + + +string(12) "Hello World!" + + + + + +string(12) "Hello World!" + diff --git a/ext/standard/tests/general_functions/proc_open_cmd.phpt b/ext/standard/tests/general_functions/proc_open_cmd.phpt new file mode 100644 index 0000000000000..2dcc207bfe6ec --- /dev/null +++ b/ext/standard/tests/general_functions/proc_open_cmd.phpt @@ -0,0 +1,31 @@ +--TEST-- +Harden against cmd.exe hijacking +--CONFLICTS-- +all +--SKIPIF-- + +--FILE-- + 0) { + foreach ($read as $stream) { + fpassthru($stream); + } +} +@unlink("cmd.exe"); +?> +--EXPECTF-- +resource(%d) of type (process) +hello +--CLEAN-- + diff --git a/ext/standard/tests/helpers/bad_cmd.c b/ext/standard/tests/helpers/bad_cmd.c new file mode 100644 index 0000000000000..05de19f5686cf --- /dev/null +++ b/ext/standard/tests/helpers/bad_cmd.c @@ -0,0 +1,7 @@ +#include + +int main() +{ + printf("pwnd!\n"); + return 0; +} diff --git a/ext/standard/tests/http/gh16810.phpt b/ext/standard/tests/http/gh16810.phpt new file mode 100644 index 0000000000000..4aa563b57b270 --- /dev/null +++ b/ext/standard/tests/http/gh16810.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug #79265 variation: "host:" not at start of header +--INI-- +allow_url_fopen=1 +--SKIPIF-- + +--FILE-- + [ +'timeout' => PHP_INT_MIN, +], +]; +$ctx = stream_context_create($config); +var_dump(fopen($uri, "r", false, $ctx)); + +$config['http']['timeout'] = PHP_INT_MAX; +$ctx = stream_context_create($config); +var_dump(fopen($uri, "r", false, $ctx)); +?> +--EXPECTF-- +resource(%d) of type (stream) + +Warning: fopen(http://www.example.com): Failed to open stream: timeout must be lower than %d in %s on line %d +bool(false) diff --git a/ext/standard/tests/streams/bug51056.phpt b/ext/standard/tests/streams/bug51056.phpt index e011405298c24..ac5909da7a55c 100644 --- a/ext/standard/tests/streams/bug51056.phpt +++ b/ext/standard/tests/streams/bug51056.phpt @@ -4,8 +4,8 @@ Bug #51056 (fread() on blocking stream will block even if data is available) +--CLEAN-- + +--EXPECT-- +array(1) { + [0]=> + string(3) "foo" +} diff --git a/ext/standard/tests/streams/stream_context_tcp_nodelay_server.phpt b/ext/standard/tests/streams/stream_context_tcp_nodelay_server.phpt index c4c3b94d3c17c..6f656ca15f9cc 100644 --- a/ext/standard/tests/streams/stream_context_tcp_nodelay_server.phpt +++ b/ext/standard/tests/streams/stream_context_tcp_nodelay_server.phpt @@ -2,6 +2,13 @@ stream context tcp_nodelay server --EXTENSIONS-- sockets +--SKIPIF-- + --FILE-- 0); + $si = socket_get_option(socket_import_stream($server), SOL_TCP, TCP_NODELAY) > 0 ? "nodelay": "delay"; + $ci = socket_get_option(socket_import_stream($conn), SOL_TCP, TCP_NODELAY) > 0 ? "nodelay": "delay"; - var_dump(socket_get_option( - socket_import_stream($client), - SOL_TCP, TCP_NODELAY) > 0); - - fclose($client); - fclose($server); + phpt_notify(message:"server-$si:conn-$ci"); CODE; $clientCode = <<<'CODE' - $test = stream_socket_client( - "tcp://127.0.0.1:9099", $errno, $errstr, 10); - - sleep(1); + $test = stream_socket_client("tcp://{{ ADDR }}", $errno, $errstr, 10); - fclose($test); + echo phpt_wait(); CODE; -include sprintf( - "%s/../../../openssl/tests/ServerClientTestCase.inc", - __DIR__); -ServerClientTestCase::getInstance()->run($serverCode, $clientCode); +include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__); +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); ?> --EXPECT-- -bool(false) -bool(true) +server-delay:conn-nodelay diff --git a/ext/standard/user_filters.c b/ext/standard/user_filters.c index 063895e2f4049..737237f6630cd 100644 --- a/ext/standard/user_filters.c +++ b/ext/standard/user_filters.c @@ -516,13 +516,17 @@ PHP_FUNCTION(stream_filter_register) fdat = ecalloc(1, sizeof(struct php_user_filter_data)); fdat->classname = zend_string_copy(classname); - if (zend_hash_add_ptr(BG(user_filter_map), filtername, fdat) != NULL && - php_stream_filter_register_factory_volatile(filtername, &user_filter_factory) == SUCCESS) { - RETVAL_TRUE; + if (zend_hash_add_ptr(BG(user_filter_map), filtername, fdat) != NULL) { + if (php_stream_filter_register_factory_volatile(filtername, &user_filter_factory) == SUCCESS) { + RETURN_TRUE; + } + + zend_hash_del(BG(user_filter_map), filtername); } else { zend_string_release_ex(classname, 0); efree(fdat); - RETVAL_FALSE; } + + RETURN_FALSE; } /* }}} */ diff --git a/ext/xml/tests/gh17187_1.phpt b/ext/xml/tests/gh17187_1.phpt new file mode 100644 index 0000000000000..4de08b33bdb81 --- /dev/null +++ b/ext/xml/tests/gh17187_1.phpt @@ -0,0 +1,93 @@ +--TEST-- +GH-17187 (unreachable program point in zend_hash) +--EXTENSIONS-- +xml +--CREDITS-- +chongwick +--FILE-- +parser = xml_parser_create(); + xml_set_element_handler($this->parser, function ($parser, $name, $attrs) { + echo "open\n"; + var_dump($name, $attrs); + $this->arrayCopy = [$this]; // Create cycle intentionally + $this->immutableData = $this->arrayCopy; + }, function ($parser, $name) { + echo "close\n"; + var_dump($name); + }); + } + + public function parseXml($xml) { + $this->immutableData = array(); + xml_parse_into_struct($this->parser, $xml, $this->immutableData, $this->immutableData); + return $this->immutableData; + } +} +$immutableParser = new ImmutableParser(); +$xml = ""; +$immutableData = $immutableParser->parseXml($xml); +var_dump($immutableData); +?> +--EXPECT-- +open +string(9) "CONTAINER" +array(0) { +} +open +string(5) "CHILD" +array(0) { +} +close +string(5) "CHILD" +close +string(9) "CONTAINER" +array(5) { + [0]=> + object(ImmutableParser)#1 (3) { + ["parser":"ImmutableParser":private]=> + object(XMLParser)#2 (0) { + } + ["immutableData":"ImmutableParser":private]=> + *RECURSION* + ["arrayCopy":"ImmutableParser":private]=> + array(1) { + [0]=> + *RECURSION* + } + } + ["CHILD"]=> + array(1) { + [0]=> + int(1) + } + [1]=> + array(3) { + ["tag"]=> + string(5) "CHILD" + ["type"]=> + string(8) "complete" + ["level"]=> + int(2) + } + ["CONTAINER"]=> + array(1) { + [0]=> + int(2) + } + [2]=> + array(3) { + ["tag"]=> + string(9) "CONTAINER" + ["type"]=> + string(5) "close" + ["level"]=> + int(1) + } +} diff --git a/ext/xml/tests/gh17187_2.phpt b/ext/xml/tests/gh17187_2.phpt new file mode 100644 index 0000000000000..9a43c92cefc03 --- /dev/null +++ b/ext/xml/tests/gh17187_2.phpt @@ -0,0 +1,53 @@ +--TEST-- +GH-17187 (unreachable program point in zend_hash) +--EXTENSIONS-- +xml +--CREDITS-- +chongwick +--FILE-- +parser = xml_parser_create(); + xml_set_element_handler($this->parser, function ($parser, $name, $attrs) { + echo "open\n"; + var_dump($name, $attrs); + $this->immutableData1 = 0xdead; + $this->immutableData2 = 0xbeef; + }, function ($parser, $name) { + echo "close\n"; + var_dump($name); + }); + } + + public function parseXml($xml) { + $this->immutableData1 = array(); + $this->immutableData2 = array(); + xml_parse_into_struct($this->parser, $xml, $this->immutableData1, $this->immutableData2); + } +} +$immutableParser = new ImmutableParser(); +$xml = ""; +$immutableParser->parseXml($xml); +var_dump($immutableParser->immutableData1); +var_dump($immutableParser->immutableData2); +?> +--EXPECT-- +open +string(9) "CONTAINER" +array(0) { +} +open +string(5) "CHILD" +array(0) { +} +close +string(5) "CHILD" +close +string(9) "CONTAINER" +int(57005) +int(48879) diff --git a/ext/xml/xml.c b/ext/xml/xml.c index 73b51b2143df9..62507a5d1307f 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -72,7 +72,7 @@ typedef struct { /* We return a pointer to these zvals in get_gc(), so it's * important that a) they are adjacent b) object is the first * and c) the number of zvals is kept up to date. */ -#define XML_PARSER_NUM_ZVALS 12 +#define XML_PARSER_NUM_ZVALS 14 zval object; zval startElementHandler; zval endElementHandler; @@ -85,6 +85,8 @@ typedef struct { zval unknownEncodingHandler; zval startNamespaceDeclHandler; zval endNamespaceDeclHandler; + zval data; + zval info; zend_function *startElementPtr; zend_function *endElementPtr; @@ -98,12 +100,10 @@ typedef struct { zend_function *startNamespaceDeclPtr; zend_function *endNamespaceDeclPtr; - zval data; - zval info; int level; int toffset; int curtag; - zval *ctag; + zend_long ctag_index; char **ltags; int lastwasopen; int skipwhite; @@ -326,6 +326,8 @@ static void xml_parser_free_obj(zend_object *object) { xml_parser *parser = xml_parser_from_obj(object); + zval_ptr_dtor(&parser->info); + zval_ptr_dtor(&parser->data); if (parser->parser) { XML_ParserFree(parser->parser); } @@ -551,15 +553,18 @@ static void _xml_add_to_info(xml_parser *parser, const char *name) { zval *element; - if (Z_ISUNDEF(parser->info)) { + if (Z_ISUNDEF(parser->info) || UNEXPECTED(Z_TYPE_P(Z_REFVAL(parser->info)) != IS_ARRAY)) { return; } + SEPARATE_ARRAY(Z_REFVAL(parser->info)); + zend_array *arr = Z_ARRVAL_P(Z_REFVAL(parser->info)); + size_t name_len = strlen(name); - if ((element = zend_hash_str_find(Z_ARRVAL(parser->info), name, name_len)) == NULL) { + if ((element = zend_hash_str_find(arr, name, name_len)) == NULL) { zval values; array_init(&values); - element = zend_hash_str_update(Z_ARRVAL(parser->info), name, name_len, &values); + element = zend_hash_str_update(arr, name, name_len, &values); } add_next_index_long(element, parser->curtag); @@ -583,6 +588,28 @@ static zend_string *_xml_decode_tag(xml_parser *parser, const XML_Char *tag) } /* }}} */ +static zval *xml_get_separated_data(xml_parser *parser) +{ + if (EXPECTED(Z_TYPE_P(Z_REFVAL(parser->data)) == IS_ARRAY)) { + SEPARATE_ARRAY(Z_REFVAL(parser->data)); + return Z_REFVAL(parser->data); + } + return NULL; +} + +static zval *xml_get_ctag(xml_parser *parser) +{ + zval *data = xml_get_separated_data(parser); + if (EXPECTED(data)) { + zval *zv = zend_hash_index_find_deref(Z_ARRVAL_P(data), parser->ctag_index); + if (EXPECTED(zv && Z_TYPE_P(zv) == IS_ARRAY)) { + SEPARATE_ARRAY(zv); + return zv; + } + } + return NULL; +} + /* {{{ _xml_startElementHandler() */ void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Char **attributes) { @@ -662,7 +689,19 @@ void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Ch zval_ptr_dtor(&atr); } - parser->ctag = zend_hash_next_index_insert(Z_ARRVAL(parser->data), &tag); + zval *data = xml_get_separated_data(parser); + if (EXPECTED(data)) { + /* Note: due to array resizes or user interference, + * we have to store an index instead of a zval into the array's memory. */ + zend_array *arr = Z_ARRVAL_P(data); + if (EXPECTED(zend_hash_next_index_insert(arr, &tag))) { + parser->ctag_index = arr->nNextFreeElement - 1; + } else { + zval_ptr_dtor(&tag); + } + } else { + zval_ptr_dtor(&tag); + } } else if (parser->level == (XML_MAXLEVEL + 1)) { php_error_docref(NULL, E_WARNING, "Maximum depth exceeded - Results truncated"); } @@ -697,17 +736,21 @@ void _xml_endElementHandler(void *userData, const XML_Char *name) zval tag; if (parser->lastwasopen) { - add_assoc_string(parser->ctag, "type", "complete"); + zval *zv = xml_get_ctag(parser); + if (EXPECTED(zv)) { + add_assoc_string(zv, "type", "complete"); + } } else { - array_init(&tag); - _xml_add_to_info(parser, ZSTR_VAL(tag_name) + parser->toffset); - add_assoc_string(&tag, "tag", SKIP_TAGSTART(ZSTR_VAL(tag_name))); /* cast to avoid gcc-warning */ - add_assoc_string(&tag, "type", "close"); - add_assoc_long(&tag, "level", parser->level); - - zend_hash_next_index_insert(Z_ARRVAL(parser->data), &tag); + zval *data = xml_get_separated_data(parser); + if (EXPECTED(data)) { + array_init(&tag); + add_assoc_string(&tag, "tag", SKIP_TAGSTART(ZSTR_VAL(tag_name))); /* cast to avoid gcc-warning */ + add_assoc_string(&tag, "type", "close"); + add_assoc_long(&tag, "level", parser->level); + zend_hash_next_index_insert(Z_ARRVAL_P(data), &tag); + } } parser->lastwasopen = 0; @@ -765,9 +808,15 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len) } } if (parser->lastwasopen) { + zval *ctag = xml_get_ctag(parser); + if (UNEXPECTED(!ctag)) { + zend_string_release_ex(decoded_value, false); + return; + } + zval *myval; /* check if the current tag already has a value - if yes append to that! */ - if ((myval = zend_hash_find(Z_ARRVAL_P(parser->ctag), ZSTR_KNOWN(ZEND_STR_VALUE)))) { + if ((myval = zend_hash_find(Z_ARRVAL_P(ctag), ZSTR_KNOWN(ZEND_STR_VALUE))) && Z_TYPE_P(myval) == IS_STRING) { size_t newlen = Z_STRLEN_P(myval) + ZSTR_LEN(decoded_value); Z_STR_P(myval) = zend_string_extend(Z_STR_P(myval), newlen, 0); strncpy(Z_STRVAL_P(myval) + Z_STRLEN_P(myval) - ZSTR_LEN(decoded_value), @@ -775,7 +824,7 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len) zend_string_release_ex(decoded_value, 0); } else { if (doprint || (! parser->skipwhite)) { - add_assoc_str(parser->ctag, "value", decoded_value); + add_assoc_str(ctag, "value", decoded_value); } else { zend_string_release_ex(decoded_value, 0); } @@ -783,9 +832,17 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len) } else { zval tag; zval *curtag, *mytype, *myval; - ZEND_HASH_REVERSE_FOREACH_VAL(Z_ARRVAL(parser->data), curtag) { - if ((mytype = zend_hash_str_find(Z_ARRVAL_P(curtag),"type", sizeof("type") - 1))) { - if (zend_string_equals_literal(Z_STR_P(mytype), "cdata")) { + + zval *data = xml_get_separated_data(parser); + if (UNEXPECTED(!data)) { + zend_string_release_ex(decoded_value, false); + return; + } + + ZEND_HASH_REVERSE_FOREACH_VAL(Z_ARRVAL_P(data), curtag) { + if (EXPECTED(Z_TYPE_P(curtag) == IS_ARRAY) && (mytype = zend_hash_str_find(Z_ARRVAL_P(curtag),"type", sizeof("type") - 1))) { + if (EXPECTED(Z_TYPE_P(mytype) == IS_STRING) && zend_string_equals_literal(Z_STR_P(mytype), "cdata")) { + SEPARATE_ARRAY(curtag); if ((myval = zend_hash_find(Z_ARRVAL_P(curtag), ZSTR_KNOWN(ZEND_STR_VALUE)))) { size_t newlen = Z_STRLEN_P(myval) + ZSTR_LEN(decoded_value); Z_STR_P(myval) = zend_string_extend(Z_STR_P(myval), newlen, 0); @@ -805,7 +862,7 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len) add_assoc_str(&tag, "value", decoded_value); add_assoc_string(&tag, "type", "cdata"); add_assoc_long(&tag, "level", parser->level); - zend_hash_next_index_insert(Z_ARRVAL(parser->data), &tag); + zend_hash_next_index_insert(Z_ARRVAL_P(data), &tag); } else if (parser->level == (XML_MAXLEVEL + 1)) { php_error_docref(NULL, E_WARNING, "Maximum depth exceeded - Results truncated"); } else { @@ -1266,21 +1323,21 @@ PHP_FUNCTION(xml_parse_into_struct) } if (info) { - info = zend_try_array_init(info); - if (!info) { + if (!zend_try_array_init(info)) { RETURN_THROWS(); } } - xdata = zend_try_array_init(xdata); - if (!xdata) { + if (!zend_try_array_init(xdata)) { RETURN_THROWS(); } - ZVAL_COPY_VALUE(&parser->data, xdata); + zval_ptr_dtor(&parser->data); + ZVAL_COPY(&parser->data, xdata); if (info) { - ZVAL_COPY_VALUE(&parser->info, info); + zval_ptr_dtor(&parser->info); + ZVAL_COPY(&parser->info, info); } parser->level = 0; diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 6d349317384e6..b2e2756381fdc 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1449,6 +1449,41 @@ PHP_ZEND_TEST_API void bug_gh9090_void_int_char_var(int i, char *fmt, ...) { PHP_ZEND_TEST_API int gh11934b_ffi_var_test_cdata; +enum bug_gh16013_enum { + BUG_GH16013_A = 1, + BUG_GH16013_B = 2, +}; + +struct bug_gh16013_int_struct { + int field; +}; + +PHP_ZEND_TEST_API char bug_gh16013_return_char(void) { + return 'A'; +} + +PHP_ZEND_TEST_API bool bug_gh16013_return_bool(void) { + return true; +} + +PHP_ZEND_TEST_API short bug_gh16013_return_short(void) { + return 12345; +} + +PHP_ZEND_TEST_API int bug_gh16013_return_int(void) { + return 123456789; +} + +PHP_ZEND_TEST_API enum bug_gh16013_enum bug_gh16013_return_enum(void) { + return BUG_GH16013_B; +} + +PHP_ZEND_TEST_API struct bug_gh16013_int_struct bug_gh16013_return_struct(void) { + struct bug_gh16013_int_struct ret; + ret.field = 123456789; + return ret; +} + #ifdef HAVE_COPY_FILE_RANGE /** * This function allows us to simulate early return of copy_file_range by setting the limit_copy_file_range ini setting. diff --git a/main/php_version.h b/main/php_version.h index 0182b4081dba7..4e26b392955ad 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 3 -#define PHP_RELEASE_VERSION 15 -#define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.3.15-dev" -#define PHP_VERSION_ID 80315 +#define PHP_RELEASE_VERSION 16 +#define PHP_EXTRA_VERSION "" +#define PHP_VERSION "8.3.16" +#define PHP_VERSION_ID 80316 diff --git a/main/streams/glob_wrapper.c b/main/streams/glob_wrapper.c index 66f2e8e0dfc70..8772850f784f3 100644 --- a/main/streams/glob_wrapper.c +++ b/main/streams/glob_wrapper.c @@ -225,10 +225,32 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha *opened_path = zend_string_init(path, strlen(path), 0); } } + const char *pattern = path; +#ifdef ZTS + char cwd[MAXPATHLEN]; + char work_pattern[MAXPATHLEN]; + char *result; + size_t cwd_skip = 0; + if (!IS_ABSOLUTE_PATH(path, strlen(path))) { + result = VCWD_GETCWD(cwd, MAXPATHLEN); + if (!result) { + cwd[0] = '\0'; + } +# ifdef PHP_WIN32 + if (IS_SLASH(*path)) { + cwd[2] = '\0'; + } +# endif + cwd_skip = strlen(cwd)+1; + + snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, path); + pattern = work_pattern; + } +#endif pglob = ecalloc(1, sizeof(*pglob)); - if (0 != (ret = glob(path, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) { + if (0 != (ret = glob(pattern, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) { #ifdef GLOB_NOMATCH if (GLOB_NOMATCH != ret) #endif @@ -238,6 +260,21 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha } } +#ifdef ZTS + if (cwd_skip > 0) { + /* strip prepended CWD */ + for (i = 0; i < pglob->glob.gl_pathc; i++) { + char *p = pglob->glob.gl_pathv[i]; + char *q = p + cwd_skip; + char *e = p + strlen(pglob->glob.gl_pathv[i]) - 1; + while (q <= e) { + *p++ = *q++; + } + *p = '\0'; + } + } +#endif + /* if open_basedir in use, check and filter restricted paths */ if ((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) { pglob->open_basedir_used = true; diff --git a/run-tests.php b/run-tests.php index 2716f2a520a74..d51ab99a205a3 100755 --- a/run-tests.php +++ b/run-tests.php @@ -3144,18 +3144,6 @@ function get_summary(bool $show_ext_summary): string $failed_test_summary .= "=====================================================================\n"; } - if (count($PHP_FAILED_TESTS['XFAILED'])) { - $failed_test_summary .= ' -===================================================================== -EXPECTED FAILED TEST SUMMARY ---------------------------------------------------------------------- -'; - foreach ($PHP_FAILED_TESTS['XFAILED'] as $failed_test_data) { - $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; - } - $failed_test_summary .= "=====================================================================\n"; - } - if (count($PHP_FAILED_TESTS['BORKED'])) { $failed_test_summary .= ' ===================================================================== @@ -3206,19 +3194,6 @@ function get_summary(bool $show_ext_summary): string $failed_test_summary .= "=====================================================================\n"; } - if (count($PHP_FAILED_TESTS['XLEAKED'])) { - $failed_test_summary .= ' -===================================================================== -EXPECTED LEAK TEST SUMMARY ---------------------------------------------------------------------- -'; - foreach ($PHP_FAILED_TESTS['XLEAKED'] as $failed_test_data) { - $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; - } - - $failed_test_summary .= "=====================================================================\n"; - } - if ($failed_test_summary && !getenv('NO_PHPTEST_SUMMARY')) { $summary .= $failed_test_summary; } diff --git a/sapi/embed/README.md b/sapi/embed/README.md index c90ff354ab7d9..87b144b4b120d 100644 --- a/sapi/embed/README.md +++ b/sapi/embed/README.md @@ -36,12 +36,12 @@ To compile this, we must point the compiler to the PHP header files. The paths t We must also point the linker and the runtime loader to the `libphp.so` shared lib for linking PHP (`-lphp`) which is located at `$(php-config --prefix)/lib`. So the complete command to compile ends up being: ```bash -$ gcc \ +$ cc \ $(php-config --includes) \ -L$(php-config --prefix)/lib \ embed_sapi_basic_example.c \ -lphp \ - -Wl,-rpath=$(php-config --prefix)/lib + -Wl,-rpath,$(php-config --prefix)/lib ``` > :memo: The embed SAPI is disabled by default. In order for the above example to compile, PHP must be built with the embed SAPI enabled. To see what SAPIs are installed, run `php-config --php-sapis`. If you don't see `embed` in the list, you'll need to rebuild PHP with `./configure --enable-embed`. The PHP shared library `libphp.so` is built when the embed SAPI is enabled. diff --git a/sapi/fpm/fpm/fpm_atomic.h b/sapi/fpm/fpm/fpm_atomic.h index e3926e708c542..02009f6af9118 100644 --- a/sapi/fpm/fpm/fpm_atomic.h +++ b/sapi/fpm/fpm/fpm_atomic.h @@ -156,6 +156,25 @@ static inline int fpm_spinlock(atomic_t *lock, int try_once) /* {{{ */ } /* }}} */ +static inline int fpm_spinlock_with_max_retries(atomic_t *lock, unsigned int max_retries) +{ + unsigned int retries = 0; + + for (;;) { + if (atomic_cmp_set(lock, 0, 1)) { + return 1; + } + + sched_yield(); + + if (++retries > max_retries) { + return 0; + } + } + + return 1; +} + #define fpm_unlock(lock) lock = 0 #endif diff --git a/sapi/fpm/fpm/fpm_config.h b/sapi/fpm/fpm/fpm_config.h index d34f686a6fbd1..a637326ed767a 100644 --- a/sapi/fpm/fpm/fpm_config.h +++ b/sapi/fpm/fpm/fpm_config.h @@ -2,6 +2,16 @@ #include +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif + /* Solaris does not have it */ #ifndef INADDR_NONE # define INADDR_NONE (-1) diff --git a/sapi/fpm/fpm/fpm_scoreboard.c b/sapi/fpm/fpm/fpm_scoreboard.c index 52d10a0416832..a4611d5edb620 100644 --- a/sapi/fpm/fpm/fpm_scoreboard.c +++ b/sapi/fpm/fpm/fpm_scoreboard.c @@ -73,6 +73,22 @@ int fpm_scoreboard_init_main(void) return 0; } +static inline void fpm_scoreboard_readers_decrement(struct fpm_scoreboard_s *scoreboard) +{ + fpm_spinlock(&scoreboard->lock, 1); + if (scoreboard->reader_count > 0) { + scoreboard->reader_count -= 1; + } +#ifdef PHP_FPM_ZLOG_TRACE + unsigned int current_reader_count = scoreboard->reader_count; +#endif + fpm_unlock(scoreboard->lock); +#ifdef PHP_FPM_ZLOG_TRACE + /* this is useful for debugging but currently needs to be hidden as external logger would always log it */ + zlog(ZLOG_DEBUG, "scoreboard: for proc %d reader decremented to value %u", getpid(), current_reader_count); +#endif +} + static struct fpm_scoreboard_s *fpm_scoreboard_get_for_update(struct fpm_scoreboard_s *scoreboard) /* {{{ */ { if (!scoreboard) { @@ -93,7 +109,33 @@ void fpm_scoreboard_update_begin(struct fpm_scoreboard_s *scoreboard) /* {{{ */ return; } - fpm_spinlock(&scoreboard->lock, 0); + int retries = 0; + while (1) { + fpm_spinlock(&scoreboard->lock, 1); + if (scoreboard->reader_count == 0) { + if (!fpm_spinlock_with_max_retries(&scoreboard->writer_active, FPM_SCOREBOARD_SPINLOCK_MAX_RETRIES)) { + /* in this case the writer might have crashed so just warn and continue as the lock was acquired */ + zlog(ZLOG_WARNING, "scoreboard: writer %d waited too long for another writer to release lock.", getpid()); + } +#ifdef PHP_FPM_ZLOG_TRACE + else { + zlog(ZLOG_DEBUG, "scoreboard: writer lock acquired by writer %d", getpid()); + } +#endif + fpm_unlock(scoreboard->lock); + break; + } + fpm_unlock(scoreboard->lock); + + if (++retries > FPM_SCOREBOARD_SPINLOCK_MAX_RETRIES) { + /* decrement reader count by 1 (assuming a killed or crashed reader) */ + fpm_scoreboard_readers_decrement(scoreboard); + zlog(ZLOG_WARNING, "scoreboard: writer detected a potential crashed reader, decrementing reader count."); + retries = 0; + } + + sched_yield(); + } } /* }}} */ @@ -170,7 +212,10 @@ void fpm_scoreboard_update_commit( scoreboard->active_max = scoreboard->active; } - fpm_unlock(scoreboard->lock); + fpm_unlock(scoreboard->writer_active); +#ifdef PHP_FPM_ZLOG_TRACE + zlog(ZLOG_DEBUG, "scoreboard: writer lock released by writer %d", getpid()); +#endif } /* }}} */ @@ -234,16 +279,37 @@ struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_chil struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang) /* {{{ */ { - struct fpm_scoreboard_s *s; - - s = scoreboard ? scoreboard : fpm_scoreboard; + struct fpm_scoreboard_s *s = scoreboard ? scoreboard : fpm_scoreboard; if (!s) { return NULL; } - if (!fpm_spinlock(&s->lock, nohang)) { - return NULL; + int retries = 0; + while (1) { + /* increment reader if no writer active */ + fpm_spinlock(&s->lock, 1); + if (!s->writer_active) { + s->reader_count += 1; +#ifdef PHP_FPM_ZLOG_TRACE + unsigned int current_reader_count = s->reader_count; +#endif + fpm_unlock(s->lock); +#ifdef PHP_FPM_ZLOG_TRACE + zlog(ZLOG_DEBUG, "scoreboard: for proc %d reader incremented to value %u", getpid(), current_reader_count); +#endif + break; + } + fpm_unlock(s->lock); + + sched_yield(); + + if (++retries > FPM_SCOREBOARD_SPINLOCK_MAX_RETRIES) { + zlog(ZLOG_WARNING, "scoreboard: reader waited too long for writer to release lock."); + fpm_scoreboard_readers_decrement(s); + return NULL; + } } + return s; } /* }}} */ @@ -253,7 +319,7 @@ void fpm_scoreboard_release(struct fpm_scoreboard_s *scoreboard) { return; } - scoreboard->lock = 0; + fpm_scoreboard_readers_decrement(scoreboard); } struct fpm_scoreboard_s *fpm_scoreboard_copy(struct fpm_scoreboard_s *scoreboard, int copy_procs) diff --git a/sapi/fpm/fpm/fpm_scoreboard.h b/sapi/fpm/fpm/fpm_scoreboard.h index c488c64bfefc4..31824940b3f7b 100644 --- a/sapi/fpm/fpm/fpm_scoreboard.h +++ b/sapi/fpm/fpm/fpm_scoreboard.h @@ -18,6 +18,8 @@ #define FPM_SCOREBOARD_LOCK_HANG 0 #define FPM_SCOREBOARD_LOCK_NOHANG 1 +#define FPM_SCOREBOARD_SPINLOCK_MAX_RETRIES 50000 + struct fpm_scoreboard_proc_s { union { atomic_t lock; @@ -52,6 +54,8 @@ struct fpm_scoreboard_s { atomic_t lock; char dummy[16]; }; + atomic_t writer_active; + unsigned int reader_count; char pool[32]; int pm; time_t start_epoch; diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c index 80be5fb6f476e..f44274e9d9ee4 100644 --- a/sapi/fpm/fpm/fpm_status.c +++ b/sapi/fpm/fpm/fpm_status.c @@ -598,7 +598,7 @@ int fpm_status_handle_request(void) /* {{{ */ time_buffer, (unsigned long) (now_epoch - proc->start_epoch), proc->requests, - duration.tv_sec * 1000000UL + duration.tv_usec, + (unsigned long) (duration.tv_sec * 1000000UL + duration.tv_usec), proc->request_method[0] != '\0' ? proc->request_method : "-", proc->request_uri[0] != '\0' ? proc->request_uri : "-", query_string ? "?" : "", diff --git a/sapi/fpm/tests/tester.inc b/sapi/fpm/tests/tester.inc index e6c971c32e432..c22af549ece76 100644 --- a/sapi/fpm/tests/tester.inc +++ b/sapi/fpm/tests/tester.inc @@ -401,11 +401,15 @@ class Tester bool $debug = null, string $clientTransport = 'stream' ) { - $this->configTemplate = $configTemplate; - $this->code = $code; - $this->options = $options; - $this->fileName = $fileName ?: self::getCallerFileName(); - $this->debug = $debug !== null ? $debug : (bool)getenv('TEST_FPM_DEBUG'); + $this->configTemplate = $configTemplate; + $this->code = $code; + $this->options = $options; + $this->fileName = $fileName ?: self::getCallerFileName(); + if (($debugFilter = getenv('TEST_FPM_DEBUG_FILTER')) !== false) { + $this->debug = str_contains(basename($this->fileName), $debugFilter); + } else { + $this->debug = $debug !== null ? $debug : (bool)getenv('TEST_FPM_DEBUG'); + } $this->logReader = new LogReader($this->debug); $this->logTool = new LogTool($this->logReader, $this->debug); $this->clientTransport = $clientTransport; @@ -930,6 +934,7 @@ class Tester $requestData['headers'] ?? [], $requestData['uri'] ?? null ); + $this->trace('Request params', $params); if (isset($requestData['delay'])) { usleep($requestData['delay']); diff --git a/win32/build/Makefile b/win32/build/Makefile index 9d4c1c0800dc7..1b200502119a7 100644 --- a/win32/build/Makefile +++ b/win32/build/Makefile @@ -54,7 +54,7 @@ DEBUGGER_CMD= DEBUGGER_ARGS= !endif -all: generated_files $(EXT_TARGETS) $(PECL_TARGETS) $(SAPI_TARGETS) +all: generated_files $(EXT_TARGETS) $(PECL_TARGETS) $(SAPI_TARGETS) test_helpers build_dirs: $(BUILD_DIR) $(BUILD_DIRS_SUB) $(BUILD_DIR_DEV) @@ -185,6 +185,7 @@ clean-pgo: clean-all -del /f /q $(BUILD_DIR)\$(DIST_ZIP_PECL) -del /f /q $(BUILD_DIR)\$(DIST_ZIP_TEST_PACK) +test_helpers: $(PHP_SRC_DIR)\ext\standard\tests\helpers\bad_cmd.exe !if $(PHP_TEST_INI_PATH) == "" test: set-tmp-env