diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index e8f698e4e091..e269ed336408 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -166,10 +166,10 @@ jobs: with: configurationParameters: >- ${{ matrix.asan && 'CFLAGS="-fsanitize=undefined,address -DZEND_TRACK_ARENA_ALLOC" LDFLAGS="-fsanitize=undefined,address"' || '' }} - ${{ matrix.variation && 'CFLAGS="-DZEND_RC_DEBUG=1 -DPROFITABILITY_CHECKS=0 -DZEND_VERIFY_FUNC_INFO=1 -DZEND_VERIFY_TYPE_INFERENCE" CXXFLAGS="-DZEND_VERIFY_TYPE_INFERENCE"' || '' }} + ${{ matrix.variation && 'CFLAGS="-DZEND_RC_DEBUG=1 -DPROFITABILITY_CHECKS=0 -DZEND_VERIFY_FUNC_INFO=1 -DZEND_VERIFY_TYPE_INFERENCE"' || '' }} ${{ (matrix.variation && fromJson(inputs.branch).jobs.LINUX_X64.config.variation_enable_zend_max_execution_timers) && '--enable-zend-max-execution-timers' || '' }} --${{ matrix.debug && 'enable' || 'disable' }}-debug - ${{ matrix.debug && 'CXXFLAGS="-D_GLIBCXX_ASSERTIONS"' || '' }} + ${{ (matrix.variation || matrix.debug) && format('CXXFLAGS="{0} {1}"', matrix.variation && '-DZEND_VERIFY_TYPE_INFERENCE' || '', matrix.debug && '-D_GLIBCXX_ASSERTIONS' || '') || '' }} --${{ matrix.zts && 'enable' || 'disable' }}-zts asan: ${{ matrix.asan && 'true' || 'false' }} skipSlow: ${{ (matrix.asan && !inputs.all_variations) && 'true' || 'false' }} diff --git a/UPGRADING b/UPGRADING index 6a1f1b12e4a8..a6cd3bdef1cb 100644 --- a/UPGRADING +++ b/UPGRADING @@ -32,6 +32,11 @@ PHP 8.6 UPGRADE NOTES from global scope" instead of the prior readonly modification error. ReflectionProperty::isWritable() also reports these properties accurately. + . Array access on Dom\DtdNamedNodeMap objects now returns null for negative + integer indexes instead of returning the first node. + . Array access on Dom\DtdNamedNodeMap objects now raises a ValueError when + the integer index is greater than INT_MAX instead of overflowing to a + smaller index. - GD: . imagesetstyle(), imagefilter() and imagecrop() filter their array arguments @@ -188,6 +193,11 @@ PHP 8.6 UPGRADE NOTES value is passed. . number_format() now raises a ValueError when $decimals is outside the integer range instead of silently clamping very large positive values. + . sleep() now raises a ValueError when $seconds is greater than the platform + limit (UINT_MAX seconds, or UINT_MAX / 1000 seconds on Windows) instead of + allowing the value to overflow. + . usleep() now raises a ValueError when $microseconds is greater than + UINT_MAX instead of allowing the value to overflow. . proc_open() now raises a ValueError when the $cwd argument contains NUL bytes. diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index adfc91880f29..1c602548b1ed 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -68,6 +68,8 @@ PHP 8.6 INTERNALS UPGRADE NOTES . Added Z_PARAM_ENUM(). . Added zend_enum_fetch_case_id(). . Added zend_enum_get_case_by_id(). + . Added zend_bin2hex() and zend_bin2hex_str() as helper functions to remove + dependencies on /ext/hash in various extensions. . ZEND_INI_GET_ADDR() is now a void* pointer instead of a char* pointer. This more correctly represents the generic nature of the returned pointer and allows to remove explicit casts, but possibly breaks pointer arithmetic diff --git a/Zend/tests/weakrefs/gh17442_1.phpt b/Zend/tests/weakrefs/gh17442_1.phpt index fc7f60174ed9..d535c307e3be 100644 --- a/Zend/tests/weakrefs/gh17442_1.phpt +++ b/Zend/tests/weakrefs/gh17442_1.phpt @@ -17,6 +17,6 @@ headers_sent($obj,$generator); Fatal error: Uncaught Exception: Test in %s:%d Stack trace: #0 [internal function]: class@anonymous->__destruct() -#1 %s(%d): headers_sent(NULL, 0) +#1 %s(%d): headers_sent(NULL, NULL) #2 {main} thrown in %s on line %d diff --git a/Zend/zend_string.c b/Zend/zend_string.c index 52fca0cd4346..b1b4a0e17a69 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -52,6 +52,17 @@ ZEND_API zend_string *zend_empty_string = NULL; ZEND_API zend_string *zend_one_char_string[256]; ZEND_API zend_string **zend_known_strings = NULL; +/* this is read-only, so it's ok */ +ZEND_SET_ALIGNED(16, static const char zend_hexconvtab[]) = "0123456789abcdef"; + +static zend_always_inline void zend_bin2hex_impl(char *out, const unsigned char *in, size_t in_len, const char *hexconvtab) +{ + for (size_t i = 0; i < in_len; i++) { + out[i * 2] = hexconvtab[in[i] >> 4]; + out[i * 2 + 1] = hexconvtab[in[i] & 0x0f]; + } +} + ZEND_API zend_ulong ZEND_FASTCALL zend_string_hash_func(zend_string *str) { return ZSTR_H(str) = zend_hash_func(ZSTR_VAL(str), ZSTR_LEN(str)); @@ -62,6 +73,21 @@ ZEND_API zend_ulong ZEND_FASTCALL zend_hash_func(const char *str, size_t len) return zend_inline_hash_func(str, len); } +ZEND_API void ZEND_FASTCALL zend_bin2hex(char *out, const unsigned char *in, size_t in_len) +{ + zend_bin2hex_impl(out, in, in_len, zend_hexconvtab); +} + +ZEND_API zend_string *zend_bin2hex_str(const unsigned char *in, size_t in_len) +{ + zend_string *result = zend_string_safe_alloc(in_len, 2 * sizeof(char), 0, 0); + + zend_bin2hex(ZSTR_VAL(result), in, in_len); + ZSTR_VAL(result)[in_len * 2] = '\0'; + + return result; +} + static void _str_dtor(zval *zv) { zend_string *str = Z_STR_P(zv); diff --git a/Zend/zend_string.h b/Zend/zend_string.h index e0d1c026a2f2..fdfff2bbc894 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -43,6 +43,8 @@ ZEND_API extern zend_string_init_existing_interned_func_t zend_string_init_exist ZEND_API zend_ulong ZEND_FASTCALL zend_string_hash_func(zend_string *str); ZEND_API zend_ulong ZEND_FASTCALL zend_hash_func(const char *str, size_t len); ZEND_API zend_string* ZEND_FASTCALL zend_interned_string_find_permanent(zend_string *str); +ZEND_API void ZEND_FASTCALL zend_bin2hex(char *out, const unsigned char *in, size_t in_len); +ZEND_API zend_string *zend_bin2hex_str(const unsigned char *in, size_t in_len); ZEND_API zend_string *zend_string_concat2( const char *str1, size_t str1_len, diff --git a/ext/bz2/bz2_filter.c b/ext/bz2/bz2_filter.c index 09c49fa76687..ec042a51a3b2 100644 --- a/ext/bz2/bz2_filter.c +++ b/ext/bz2/bz2_filter.c @@ -21,7 +21,7 @@ /* {{{ data structure */ -enum strm_status { +C23_ENUM(strm_status, uint8_t) { PHP_BZ2_UNINITIALIZED, PHP_BZ2_RUNNING, PHP_BZ2_FINISHED @@ -34,12 +34,11 @@ typedef struct _php_bz2_filter_data { size_t inbuf_len; size_t outbuf_len; - enum strm_status status; /* Decompress option */ - unsigned int small_footprint : 1; /* Decompress option */ - unsigned int expect_concatenated : 1; /* Decompress option */ - unsigned int is_flushed : 1; /* only for compression */ - - int persistent; + bool persistent; + bool expect_concatenated : 1; /* Decompress option */ + bool small_footprint : 1; /* Decompress option */ + bool is_flushed : 1; /* only for compression */ + strm_status status; /* Decompress option */ /* Configuration for reset - immutable */ int blockSize100k; /* compress only */ diff --git a/ext/iconv/tests/bug52211.phpt b/ext/iconv/tests/bug52211.phpt index 155fad853485..7832cbeadd00 100644 --- a/ext/iconv/tests/bug52211.phpt +++ b/ext/iconv/tests/bug52211.phpt @@ -11,8 +11,22 @@ if (PHP_OS_FAMILY === 'Solaris') { --FILE-- diff --git a/ext/iconv/tests/bug76249.phpt b/ext/iconv/tests/bug76249.phpt index 37608ccc0447..2fa9b8cc0500 100644 --- a/ext/iconv/tests/bug76249.phpt +++ b/ext/iconv/tests/bug76249.phpt @@ -4,16 +4,27 @@ Bug #76249 (stream filter convert.iconv leads to infinite loop on invalid sequen iconv --FILE-- DONE ---EXPECTF-- -Warning: stream_get_contents(): iconv stream filter ("ucs-2"=>"utf%A8//IGNORE"): invalid multibyte sequence in %sbug76249.php on line %d -string(0) "" +--EXPECTREGEX-- +Warning: stream_get_contents\(\): iconv stream filter \("ucs-2"=>"utf-?8(\/\/IGNORE)?"\): invalid multibyte sequence in .*bug76249\.php on line \d+ +string\(0\) "" DONE diff --git a/ext/iconv/tests/eucjp2iso2022jp.phpt b/ext/iconv/tests/eucjp2iso2022jp.phpt index 490e772c80c2..db48ea627140 100644 --- a/ext/iconv/tests/eucjp2iso2022jp.phpt +++ b/ext/iconv/tests/eucjp2iso2022jp.phpt @@ -7,6 +7,13 @@ iconv if (PHP_OS_FAMILY === 'Solaris') { die("skip Solaris iconv behaves differently"); } +// ISO-2022-JP is a stateful encoding, so the right answer is not +// unique. In particular, musl (type "unknown") is known to have an +// inefficient encoding for it that does not agree with the expected +// output below. +if (ICONV_IMPL == "unknown") { + die("skip byte-comparison of stateful encoding with unknown iconv"); +} ?> --INI-- error_reporting=2039 @@ -22,8 +29,8 @@ function hexdump($str) { print "\n"; } -$str = str_repeat("ÆüËÜ¸ì¥Æ¥­¥¹¥È¤È English text", 30); -$str .= "ÆüËܸì"; +$str = str_repeat("���ܸ�ƥ����Ȥ� English text", 30); +$str .= "���ܸ�"; echo hexdump(iconv("EUC-JP", "ISO-2022-JP", $str)); ?> diff --git a/ext/iconv/tests/iconv_mime_encode.phpt b/ext/iconv/tests/iconv_mime_encode.phpt index 9cf906a73e61..75c9b56e4291 100644 --- a/ext/iconv/tests/iconv_mime_encode.phpt +++ b/ext/iconv/tests/iconv_mime_encode.phpt @@ -6,6 +6,13 @@ iconv iconv.internal_charset=iso-8859-1 --SKIPIF-- +--EXPECTF-- +headers_sent(line: $line) prior to sending headers +headers_sent(): +bool(false) +headers_list(): +array(0) { +} +$file: +NULL +$line: +int(0) +headers_sent(filename: $file) prior to sending headers +headers_sent(): +bool(false) +headers_list(): +array(0) { +} +$file: +string(0) "" +$line: +NULL +header(): +NULL +headers_sent(line: $line) after sending headers +headers_sent(): +bool(true) +headers_list(): +array(0) { +} +$file: +NULL +$line: +int(39) +headers_sent(filename: $file) after sending headers +headers_sent(): +bool(true) +headers_list(): +array(0) { +} +$file: +string(%d) "%s" +$line: +NULL +Done diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c index f4e4ef81af2f..1233f0430121 100644 --- a/sapi/phpdbg/phpdbg_bp.c +++ b/sapi/phpdbg/phpdbg_bp.c @@ -1500,33 +1500,24 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type) /* {{{ */ switch (brake->type) { case PHPDBG_BREAK_METHOD_OPLINE: str_type = "method"; - goto print_opline; + break; case PHPDBG_BREAK_FUNCTION_OPLINE: str_type = "function"; - goto print_opline; + break; case PHPDBG_BREAK_FILE_OPLINE: - str_type = "method"; - - print_opline: { - if (brake->type == PHPDBG_BREAK_METHOD_OPLINE) { - str_type = "method"; - } else if (brake->type == PHPDBG_BREAK_FUNCTION_OPLINE) { - str_type = "function"; - } else if (brake->type == PHPDBG_BREAK_FILE_OPLINE) { - str_type = "file"; - } - - phpdbg_writeln("#%d\t\t#"ZEND_ULONG_FMT"\t\t(%s breakpoint)%s", - brake->id, brake->opline, str_type, - ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); - } break; + str_type = "file"; + break; default: phpdbg_writeln("#%d\t\t#"ZEND_ULONG_FMT"%s", brake->id, brake->opline, ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); - break; + continue; } + + phpdbg_writeln("#%d\t\t#"ZEND_ULONG_FMT"\t\t(%s breakpoint)%s", + brake->id, brake->opline, str_type, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); } ZEND_HASH_FOREACH_END(); } break;