diff --git a/.github/actions/configure-x32/action.yml b/.github/actions/configure-x32/action.yml index a5c5df4f7971..8b9ddd318923 100644 --- a/.github/actions/configure-x32/action.yml +++ b/.github/actions/configure-x32/action.yml @@ -3,6 +3,9 @@ inputs: configurationParameters: default: '' required: false + cflags: + default: '-m32 -msse2' + required: false runs: using: composite steps: @@ -12,8 +15,8 @@ runs: export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/lib/i386-linux-gnu/pkgconfig" ./buildconf --force - export CFLAGS="-m32 -msse2" - export CXXFLAGS="-m32 -msse2" + export CFLAGS="${{ inputs.cflags }}" + export CXXFLAGS="${{ inputs.cflags }}" export LDFLAGS=-L/usr/lib/i386-linux-gnu ./configure ${{ inputs.configurationParameters }} \ --enable-option-checking=fatal \ diff --git a/.github/matrix.php b/.github/matrix.php index ee9cb4eb05ab..7ddf640509b9 100644 --- a/.github/matrix.php +++ b/.github/matrix.php @@ -57,6 +57,7 @@ function select_jobs($repository, $trigger, $nightly, $labels, $php_version, $re $test_libmysqlclient = in_array('CI: libmysqlclient', $labels, true); $test_linux_ppc64 = in_array('CI: Linux PPC64', $labels, true); $test_linux_x32 = in_array('CI: Linux X32', $labels, true); + $test_linux_x32_int64 = in_array('CI: Linux X32 INT64', $labels, true); $test_linux_x64 = in_array('CI: Linux X64', $labels, true); $test_macos = in_array('CI: macOS', $labels, true); $test_msan = in_array('CI: MSAN', $labels, true); @@ -123,6 +124,13 @@ function select_jobs($repository, $trigger, $nightly, $labels, $php_version, $re ? ['debug' => [true, false], 'zts' => [true, false]] : ['debug' => [true], 'zts' => [true]]; } + // 32bit userland with a 64bit zend_long. Version gated because + // --enable-zend-int64 does not exist on the older branches. + if (version_compare($php_version, '8.6', '>=') && ($all_jobs || !$no_jobs || $test_linux_x32_int64)) { + $jobs['LINUX_X32_INT64']['matrix'] = $all_variations + ? ['debug' => [true, false], 'zts' => [true, false]] + : ['debug' => [true], 'zts' => [true]]; + } if ($all_jobs || !$no_jobs || $test_macos) { $test_arm = version_compare($php_version, '8.4', '>='); $jobs['MACOS']['matrix'] = $all_variations diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index ce6053f929a0..582e88dd64fd 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -306,6 +306,93 @@ jobs: jitType: function - name: Extra tests uses: ./.github/actions/extra-tests + LINUX_X32_INT64: + if: ${{ fromJson(inputs.branch).jobs.LINUX_X32_INT64 }} + strategy: + fail-fast: false + matrix: ${{ fromJson(inputs.branch).jobs.LINUX_X32_INT64.matrix }} + name: "LINUX_X32_INT64_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + runs-on: ubuntu-latest + timeout-minutes: 180 + container: + image: ubuntu:${{ fromJson(inputs.branch).config.ubuntu_version }} + env: + MYSQL_TEST_HOST: mysql + PDO_MYSQL_TEST_DSN: mysql:host=mysql;dbname=test + PDO_MYSQL_TEST_HOST: mysql + PDO_FIREBIRD_TEST_DSN: firebird:dbname=firebird:test.fdb + services: + mysql: + image: mysql:8.4 + ports: + - 3306:3306 + env: + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: root + firebird: + image: jacobalberty/firebird + ports: + - 3050:3050 + env: + ISC_PASSWORD: test + FIREBIRD_DATABASE: test.fdb + FIREBIRD_USER: test + FIREBIRD_PASSWORD: test + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: apt + uses: ./.github/actions/apt-x32 + - name: ccache + uses: ./.github/actions/ccache + with: + name: "LINUX_X32_INT64_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + - name: System info + run: | + echo "::group::Show host CPU info" + lscpu + echo "::endgroup::" + echo "::group::Show installed package versions" + dpkg -l + echo "::endgroup::" + - name: ./configure + uses: ./.github/actions/configure-x32 + with: + # x87 computes at 80bit and feeds unrounded operands into double + # arithmetic, which diverges from every 64bit platform. SSE math + # keeps the results identical. + cflags: '-m32 -msse2 -mfpmath=sse' + configurationParameters: >- + --${{ matrix.debug && 'enable' || 'disable' }}-debug + --${{ matrix.zts && 'enable' || 'disable' }}-zts + --enable-zend-int64 + - name: make + run: make -j$(/usr/bin/nproc) >/dev/null + - name: make install + uses: ./.github/actions/install-linux-x32 + - name: Test + if: ${{ inputs.all_variations }} + uses: ./.github/actions/test-linux + - name: Test Tracing JIT + uses: ./.github/actions/test-linux + with: + enableOpcache: true + jitType: tracing + - name: Test OpCache + if: ${{ inputs.all_variations }} + uses: ./.github/actions/test-linux + with: + enableOpcache: true + - name: Test Function JIT + if: ${{ inputs.all_variations }} + uses: ./.github/actions/test-linux + with: + enableOpcache: true + jitType: function + - name: Extra tests + uses: ./.github/actions/extra-tests MACOS: if: ${{ fromJson(inputs.branch).jobs.MACOS }} strategy: diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index 41da8344bf1f..9e280c200915 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -212,6 +212,7 @@ AX_CHECK_COMPILE_FLAG([-fno-common], [CFLAGS="-fno-common $CFLAGS"]) ZEND_CHECK_ALIGNMENT +ZEND_CHECK_INT64 ZEND_CHECK_SIGNALS ZEND_CHECK_MAX_EXECUTION_TIMERS ]) @@ -416,6 +417,43 @@ AS_VAR_IF([php_cv_align_mm], [failed], ]) ]) +dnl +dnl ZEND_CHECK_INT64 +dnl +dnl Check whether to enable 64 bit integer if supported by the system. +dnl +AC_DEFUN([ZEND_CHECK_INT64], [dnl + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[]], + [[ + #if !(defined(__x86_64__) || defined(__LP64__) || defined(_LP64) || defined(_WIN64)) + #error "Not a 64-bit platform" + #endif + ]] + )], + [ZEND_INT64=yes], + [ZEND_INT64=no]) + + AC_ARG_ENABLE([zend-int64], + [AS_HELP_STRING([--enable-zend-int64], [Enable 64bit integer support (enabled by default on 64bit arch)])], + [ZEND_INT64=$enableval], + [ZEND_INT64=$ZEND_INT64]) + + AS_VAR_IF([ZEND_INT64], [yes], + AC_CHECK_TYPE([int64_t],, + [AC_MSG_ERROR([int64_t not found])], + [#include ])) + + AS_VAR_IF([ZEND_INT64], [yes], + [AC_DEFINE([ZEND_INT64], [1], + [Define to 1 if zend_long as int64 is supported and enabled.]) + AS_VAR_APPEND([CFLAGS], [" -DZEND_INT64"])]) + + AC_MSG_CHECKING([whether to enable 64 bit integer support]) + AC_MSG_RESULT([$ZEND_INT64]) +]) + dnl dnl ZEND_CHECK_SIGNALS dnl diff --git a/Zend/tests/fibers/get-return-after-bailout.phpt b/Zend/tests/fibers/get-return-after-bailout.phpt index 79ab70c98baa..0d78ba2376c4 100644 --- a/Zend/tests/fibers/get-return-after-bailout.phpt +++ b/Zend/tests/fibers/get-return-after-bailout.phpt @@ -16,7 +16,8 @@ register_shutdown_function(static function (): void { }); $fiber = new Fiber(static function (): void { - str_repeat('X', PHP_INT_MAX); + $allocSize = PHP_INT_SIZE <= PHP_SYS_SIZE ? PHP_INT_MAX : 2 ** (PHP_SYS_SIZE * 8 - 1) - 1; + str_repeat('X', $allocSize); }); $fiber->start(); diff --git a/Zend/tests/int_overflow_64bit.phpt b/Zend/tests/int_overflow_64bit.phpt index cc14e14949ca..47aaa3c17262 100644 --- a/Zend/tests/int_overflow_64bit.phpt +++ b/Zend/tests/int_overflow_64bit.phpt @@ -20,6 +20,17 @@ foreach ($doubles as $d) { var_dump($l); } +/* ++ and -- overflow to float at the zend_long boundary, and must not do so + * anywhere below it. The 32-bit boundaries matter on builds where zend_long is + * wider than the platform word: they are the values a 32-bit increment would + * either wrap or wrongly report as overflowing. */ +$i = PHP_INT_MAX; $i++; var_dump($i); +$i = PHP_INT_MIN; $i--; var_dump($i); +$i = 2147483647; $i++; var_dump($i); +$i = 4294967295; $i++; var_dump($i); +$i = -2147483648; $i--; var_dump($i); +$i = -4294967296; $i--; var_dump($i); + echo "Done\n"; ?> --EXPECTF-- @@ -36,4 +47,10 @@ int(0) int(-9223372036854775808) int(-9223372036854775808) int(-9223372036854775808) +float(9.223372036854776E+18) +float(-9.223372036854776E+18) +int(2147483648) +int(4294967296) +int(-2147483649) +int(-4294967297) Done diff --git a/Zend/tests/str_offset_assign_sizet.phpt b/Zend/tests/str_offset_assign_sizet.phpt new file mode 100644 index 000000000000..1c1ad95c9a4e --- /dev/null +++ b/Zend/tests/str_offset_assign_sizet.phpt @@ -0,0 +1,69 @@ +--TEST-- +Assigning to a string offset that would exceed the maximum string length +--INI-- +memory_limit=128M +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- + $sizeMax + 11, + 'STR_MAX' => PHP_STRING_MAX_LENGTH, + 'STR_MAX+1' => PHP_STRING_MAX_LENGTH + 1, + 'STR_MAX+2' => PHP_STRING_MAX_LENGTH + 2, + 'SIZE_MAX-2' => $sizeMax - 2, + 'SIZE_MAX-1' => $sizeMax - 1, + 'SIZE_MAX' => $sizeMax, + 'INT_MAX' => PHP_INT_MAX, +]; + +foreach ($offsets as $label => $offset) { + echo "$label: "; + $s = "abc"; + try { + $s[$offset] = 'x'; + $result = 'no error'; + } catch (Error $e) { + $result = $e::class . ': ' . $e->getMessage(); + } + echo $result, '; $s = ', var_export($s, true), "\n"; +} + +/* The largest usable offset must not be refused: it reaches the allocator and + * fails there, as it would on a build where zend_long is no wider than size_t. + * + * Which diagnostic comes back depends on the build, so only the fact that it + * got that far is asserted. ZSTR_MAX_LEN does not account for the per + * allocation zend_mm_debug_info that a debug build adds, so at the very top of + * the range a debug build reports the overflow of that addition ("Possible + * integer overflow in memory allocation") while a release build has no such + * overhead, attempts the allocation for real and reports the memory limit + * ("Allowed memory size exhausted"). */ +$s = "abc"; +$s[PHP_STRING_MAX_LENGTH - 1] = 'x'; +?> +--EXPECTF-- +SIZE_MAX+11: Error: String size overflow; $s = 'abc' +STR_MAX: Error: String size overflow; $s = 'abc' +STR_MAX+1: Error: String size overflow; $s = 'abc' +STR_MAX+2: Error: String size overflow; $s = 'abc' +SIZE_MAX-2: Error: String size overflow; $s = 'abc' +SIZE_MAX-1: Error: String size overflow; $s = 'abc' +SIZE_MAX: Error: String size overflow; $s = 'abc' +INT_MAX: Error: String size overflow; $s = 'abc' + +Fatal error: %s in %s on line %d diff --git a/Zend/tests/strncmp_length_sizet.phpt b/Zend/tests/strncmp_length_sizet.phpt new file mode 100644 index 000000000000..8f719408669c --- /dev/null +++ b/Zend/tests/strncmp_length_sizet.phpt @@ -0,0 +1,41 @@ +--TEST-- +strncmp()/strncasecmp() $length must not be narrowed to size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- + 2, + '3' => 3, + 'SIZE_MAX' => $sizeMax, + 'SIZE_MAX+1' => $sizeMax + 1, + 'SIZE_MAX+3' => $sizeMax + 3, + 'INT_MAX' => PHP_INT_MAX, +]; + +foreach ($lengths as $label => $length) { + echo "$label: "; + printf("strncmp=%d strncasecmp=%d\n", + strncmp('abc', 'abd', $length), + strncasecmp('ABC', 'abd', $length)); +} +?> +--EXPECT-- +2: strncmp=0 strncasecmp=0 +3: strncmp=-1 strncasecmp=-1 +SIZE_MAX: strncmp=-1 strncasecmp=-1 +SIZE_MAX+1: strncmp=-1 strncasecmp=-1 +SIZE_MAX+3: strncmp=-1 strncasecmp=-1 +INT_MAX: strncmp=-1 strncasecmp=-1 diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index f6c0a1ad0e98..7abef47317ac 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -173,7 +173,7 @@ static size_t _real_page_size = ZEND_MM_PAGE_SIZE; #endif typedef uint32_t zend_mm_page_info; /* 4-byte integer */ -typedef zend_ulong zend_mm_bitset; /* 4-byte or 8-byte integer */ +typedef size_t zend_mm_bitset; /* 4-byte or 8-byte integer */ #define ZEND_MM_ALIGNED_OFFSET(size, alignment) \ (((size_t)(size)) & ((alignment) - 1)) @@ -568,20 +568,20 @@ static void *zend_mm_mmap(size_t size) /* Bitmask */ /***********/ -/* number of trailing set (1) bits */ -ZEND_ATTRIBUTE_CONST static zend_always_inline int zend_mm_bitset_nts(zend_mm_bitset bitset) +/* number of trailing zero (0) bits */ +ZEND_ATTRIBUTE_CONST static zend_always_inline int zend_mm_bitset_ntz(zend_mm_bitset bitset) { -#if (defined(__GNUC__) || __has_builtin(__builtin_ctzl)) && SIZEOF_ZEND_LONG == SIZEOF_LONG && defined(PHP_HAVE_BUILTIN_CTZL) - return __builtin_ctzl(~bitset); +#if (defined(__GNUC__) || __has_builtin(__builtin_ctzl)) && SIZEOF_SIZE_T == SIZEOF_LONG && defined(PHP_HAVE_BUILTIN_CTZL) + return __builtin_ctzl(bitset); #elif (defined(__GNUC__) || __has_builtin(__builtin_ctzll)) && defined(PHP_HAVE_BUILTIN_CTZLL) - return __builtin_ctzll(~bitset); + return __builtin_ctzll(bitset); #elif defined(_WIN32) unsigned long index; #if defined(_WIN64) - if (!BitScanForward64(&index, ~bitset)) { + if (!BitScanForward64(&index, bitset)) { #else - if (!BitScanForward(&index, ~bitset)) { + if (!BitScanForward(&index, bitset)) { #endif /* undefined behavior */ return 32; @@ -591,22 +591,26 @@ ZEND_ATTRIBUTE_CONST static zend_always_inline int zend_mm_bitset_nts(zend_mm_bi #else int n; - if (bitset == (zend_mm_bitset)-1) return ZEND_MM_BITSET_LEN; + if (bitset == 0) return ZEND_MM_BITSET_LEN; n = 0; -#if SIZEOF_ZEND_LONG == 8 - if (sizeof(zend_mm_bitset) == 8) { - if ((bitset & 0xffffffff) == 0xffffffff) {n += 32; bitset = bitset >> Z_UL(32);} - } +#if SIZEOF_SIZE_T == 8 + if ((bitset & 0xffffffff) == 0) {n += 32; bitset = bitset >> 32;} #endif - if ((bitset & 0x0000ffff) == 0x0000ffff) {n += 16; bitset = bitset >> 16;} - if ((bitset & 0x000000ff) == 0x000000ff) {n += 8; bitset = bitset >> 8;} - if ((bitset & 0x0000000f) == 0x0000000f) {n += 4; bitset = bitset >> 4;} - if ((bitset & 0x00000003) == 0x00000003) {n += 2; bitset = bitset >> 2;} - return n + (bitset & 1); + if ((bitset & 0x0000ffff) == 0) {n += 16; bitset = bitset >> 16;} + if ((bitset & 0x000000ff) == 0) {n += 8; bitset = bitset >> 8;} + if ((bitset & 0x0000000f) == 0) {n += 4; bitset = bitset >> 4;} + if ((bitset & 0x00000003) == 0) {n += 2; bitset = bitset >> 2;} + return n + !(bitset & 1); #endif } +/* number of trailing set (1) bits */ +ZEND_ATTRIBUTE_CONST static zend_always_inline int zend_mm_bitset_nts(zend_mm_bitset bitset) +{ + return zend_mm_bitset_ntz(~bitset); +} + static zend_always_inline int zend_mm_bitset_is_set(zend_mm_bitset *bitset, int bit) { return ZEND_BIT_TEST(bitset, bit); @@ -614,12 +618,12 @@ static zend_always_inline int zend_mm_bitset_is_set(zend_mm_bitset *bitset, int static zend_always_inline void zend_mm_bitset_set_bit(zend_mm_bitset *bitset, int bit) { - bitset[bit / ZEND_MM_BITSET_LEN] |= (Z_UL(1) << (bit & (ZEND_MM_BITSET_LEN-1))); + bitset[bit / ZEND_MM_BITSET_LEN] |= ((zend_mm_bitset)1 << (bit & (ZEND_MM_BITSET_LEN-1))); } static zend_always_inline void zend_mm_bitset_reset_bit(zend_mm_bitset *bitset, int bit) { - bitset[bit / ZEND_MM_BITSET_LEN] &= ~(Z_UL(1) << (bit & (ZEND_MM_BITSET_LEN-1))); + bitset[bit / ZEND_MM_BITSET_LEN] &= ~((zend_mm_bitset)1 << (bit & (ZEND_MM_BITSET_LEN-1))); } static zend_always_inline void zend_mm_bitset_set_range(zend_mm_bitset *bitset, int start, int len) @@ -666,7 +670,7 @@ static zend_always_inline void zend_mm_bitset_reset_range(zend_mm_bitset *bitset if (pos != end) { /* reset bits from "bit" to ZEND_MM_BITSET_LEN-1 */ - tmp = ~((Z_UL(1) << bit) - 1); + tmp = ~(((zend_mm_bitset)1 << bit) - 1); bitset[pos++] &= ~tmp; while (pos != end) { /* set all bits */ @@ -1013,7 +1017,7 @@ static void *zend_mm_alloc_pages(zend_mm_heap *heap, uint32_t pages_count ZEND_F tmp = *(bitset++); } /* find first 1 bit */ - len = (i + zend_ulong_ntz(tmp)) - page_num; + len = (i + zend_mm_bitset_ntz(tmp)) - page_num; if (len >= pages_count) { goto found; } @@ -1070,7 +1074,7 @@ static void *zend_mm_alloc_pages(zend_mm_heap *heap, uint32_t pages_count ZEND_F tmp = *(bitset++); } /* find first 1 bit */ - len = i + zend_ulong_ntz(tmp) - page_num; + len = i + zend_mm_bitset_ntz(tmp) - page_num; if (len >= pages_count) { if (len == pages_count) { goto found; @@ -1669,6 +1673,9 @@ static zend_never_inline void *zend_mm_realloc_huge(zend_mm_heap *heap, void *pt #if ZEND_DEBUG real_size = size; size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); + if (UNEXPECTED(size < real_size)) { + zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); + } #endif if (size > ZEND_MM_MAX_LARGE_SIZE) { #if ZEND_DEBUG @@ -1774,6 +1781,9 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p size_t real_size = size; size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); + if (UNEXPECTED(size < real_size)) { + zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); + } #endif ZEND_MM_CHECK(chunk->heap == heap, "zend_mm_heap corrupted"); @@ -2154,7 +2164,7 @@ static zend_mm_heap *zend_mm_init(void) chunk->free_pages = ZEND_MM_PAGES - ZEND_MM_FIRST_PAGE; chunk->free_tail = ZEND_MM_FIRST_PAGE; chunk->num = 0; - chunk->free_map[0] = (Z_L(1) << ZEND_MM_FIRST_PAGE) - 1; + chunk->free_map[0] = (1L << ZEND_MM_FIRST_PAGE) - 1; chunk->map[0] = ZEND_MM_LRUN(ZEND_MM_FIRST_PAGE); heap->main_chunk = chunk; heap->cached_chunks = NULL; @@ -2174,7 +2184,7 @@ static zend_mm_heap *zend_mm_init(void) #endif zend_mm_init_key(heap); #if ZEND_MM_LIMIT - heap->limit = (size_t)Z_L(-1) >> 1; + heap->limit = (size_t)-1 >> 1; heap->overflow = 0; #endif #if ZEND_MM_CUSTOM @@ -2426,7 +2436,7 @@ static void zend_mm_check_leaks(zend_mm_heap *heap) repeated = zend_mm_find_leaks_huge(heap, list); total += 1 + repeated; if (repeated) { - zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(uintptr_t)repeated); + zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, ZEND_ULONG_TO_PTR(repeated)); } heap->huge_list = list = list->next; @@ -2465,7 +2475,7 @@ static void zend_mm_check_leaks(zend_mm_heap *heap) zend_mm_find_leaks(heap, p, i + bin_pages[bin_num], &leak); total += 1 + repeated; if (repeated) { - zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(uintptr_t)repeated); + zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, ZEND_ULONG_TO_PTR(repeated)); } } dbg = (zend_mm_debug_info*)((char*)dbg + bin_data_size[bin_num]); @@ -2491,7 +2501,7 @@ static void zend_mm_check_leaks(zend_mm_heap *heap) repeated = zend_mm_find_leaks(heap, p, i + pages_count, &leak); total += 1 + repeated; if (repeated) { - zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(uintptr_t)repeated); + zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, ZEND_ULONG_TO_PTR(repeated)); } i += pages_count; } @@ -3079,14 +3089,14 @@ static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) #if ZEND_MM_CUSTOM static zend_always_inline void tracked_add(zend_mm_heap *heap, void *ptr, size_t size) { zval size_zv; - zend_ulong h = ((uintptr_t) ptr) >> ZEND_MM_ALIGNMENT_LOG2; - ZEND_ASSERT((void *) (uintptr_t) (h << ZEND_MM_ALIGNMENT_LOG2) == ptr); + zend_ulong h = ZEND_PTR_TO_ZEND_ULONG(ptr) >> ZEND_MM_ALIGNMENT_LOG2; + ZEND_ASSERT(ZEND_ULONG_TO_PTR(h << ZEND_MM_ALIGNMENT_LOG2) == ptr); ZVAL_LONG(&size_zv, size); zend_hash_index_add_new(heap->tracked_allocs, h, &size_zv); } static zend_always_inline zval *tracked_get_size_zv(zend_mm_heap *heap, void *ptr) { - zend_ulong h = ((uintptr_t) ptr) >> ZEND_MM_ALIGNMENT_LOG2; + zend_ulong h = ZEND_PTR_TO_ZEND_ULONG(ptr) >> ZEND_MM_ALIGNMENT_LOG2; zval *size_zv = zend_hash_index_find(heap->tracked_allocs, h); ZEND_ASSERT(size_zv && "Trying to free pointer not allocated through ZendMM"); return size_zv; @@ -3172,7 +3182,7 @@ static void tracked_free_all(zend_mm_heap *heap) { HashTable *tracked_allocs = heap->tracked_allocs; zend_ulong h; ZEND_HASH_FOREACH_NUM_KEY(tracked_allocs, h) { - void *ptr = (void *) (uintptr_t) (h << ZEND_MM_ALIGNMENT_LOG2); + void *ptr = ZEND_ULONG_TO_PTR(h << ZEND_MM_ALIGNMENT_LOG2); free(ptr); } ZEND_HASH_FOREACH_END(); } @@ -3383,7 +3393,7 @@ static void alloc_globals_ctor(zend_alloc_globals *alloc_globals) zend_mm_heap *mm_heap = alloc_globals->mm_heap = malloc(sizeof(zend_mm_heap)); memset(mm_heap, 0, sizeof(zend_mm_heap)); mm_heap->use_custom_heap = ZEND_MM_CUSTOM_HEAP_STD; - mm_heap->limit = (size_t)Z_L(-1) >> 1; + mm_heap->limit = (size_t)-1 >> 1; mm_heap->overflow = 0; if (!tracked) { @@ -3586,7 +3596,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void chunk->free_pages = ZEND_MM_PAGES - ZEND_MM_FIRST_PAGE; chunk->free_tail = ZEND_MM_FIRST_PAGE; chunk->num = 0; - chunk->free_map[0] = (Z_L(1) << ZEND_MM_FIRST_PAGE) - 1; + chunk->free_map[0] = (1L << ZEND_MM_FIRST_PAGE) - 1; chunk->map[0] = ZEND_MM_LRUN(ZEND_MM_FIRST_PAGE); heap->main_chunk = chunk; heap->cached_chunks = NULL; @@ -3606,7 +3616,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void #endif zend_mm_init_key(heap); #if ZEND_MM_LIMIT - heap->limit = (size_t)Z_L(-1) >> 1; + heap->limit = (size_t)-1 >> 1; heap->overflow = 0; #endif #if ZEND_MM_CUSTOM diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index e02e0afe2bfc..3a1b0c60805c 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -404,6 +404,7 @@ ZEND_FUNCTION(strncmp) { zend_string *s1, *s2; zend_long len; + size_t cmp_len; ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_STR(s1) @@ -416,7 +417,9 @@ ZEND_FUNCTION(strncmp) RETURN_THROWS(); } - RETURN_LONG(zend_binary_strncmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2), len)); + cmp_len = ZEND_LONG_SIZE_T_OVFL(len) ? SIZE_MAX : (size_t) len; + + RETURN_LONG(zend_binary_strncmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2), cmp_len)); } /* }}} */ @@ -439,6 +442,7 @@ ZEND_FUNCTION(strncasecmp) { zend_string *s1, *s2; zend_long len; + size_t cmp_len; ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_STR(s1) @@ -451,7 +455,9 @@ ZEND_FUNCTION(strncasecmp) RETURN_THROWS(); } - RETURN_LONG(zend_binary_strncasecmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2), len)); + cmp_len = ZEND_LONG_SIZE_T_OVFL(len) ? SIZE_MAX : (size_t) len; + + RETURN_LONG(zend_binary_strncasecmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2), cmp_len)); } /* }}} */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 5aa1b07f304d..7c2db4ee000b 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -12966,7 +12966,7 @@ static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ } else if (Z_TYPE_P(dim) != IS_STRING || is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, 1) != IS_LONG) { return; } - if (offset < 0 || (size_t)offset >= Z_STRLEN_P(container)) { + if (offset < 0 || ZEND_SIZE_T_LTE_ZEND_LONG(Z_STRLEN_P(container), offset)) { return; } c = (uint8_t) Z_STRVAL_P(container)[offset]; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 14a340ffee37..cf1228c3cb6b 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2160,11 +2160,20 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, } } - if ((size_t)offset >= ZSTR_LEN(s)) { + if (ZEND_SIZE_T_LTE_ZEND_LONG(ZSTR_LEN(s), offset)) { +#if SIZEOF_SIZE_T < SIZEOF_ZEND_LONG + if (UNEXPECTED(offset >= (zend_long) ZSTR_MAX_LEN)) { + zend_throw_error(NULL, "String size overflow"); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } + return; + } +#endif /* Extend string if needed */ - zend_long old_len = ZSTR_LEN(s); + size_t old_len = ZSTR_LEN(s); ZVAL_NEW_STR(str, zend_string_extend(s, (size_t)offset + 1, 0)); - memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len); + memset(Z_STRVAL_P(str) + old_len, ' ', (size_t)offset - old_len); Z_STRVAL_P(str)[offset+1] = 0; } else { zend_string_forget_hash_val(Z_STR_P(str)); @@ -3150,7 +3159,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, c } out: - if (UNEXPECTED(ZSTR_LEN(str) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) { + if (UNEXPECTED(ZEND_SIZE_T_LT_ZEND_ULONG(ZSTR_LEN(str), ((offset < 0) ? -(zend_ulong)offset : ((zend_ulong)offset + 1))))) { if (type != BP_VAR_IS) { zend_error(E_WARNING, "Uninitialized string offset " ZEND_LONG_FMT, offset); ZVAL_EMPTY_STRING(result); @@ -3311,7 +3320,7 @@ static zend_never_inline bool ZEND_FASTCALL zend_isset_dim_slow(const zval *cont if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ lval += (zend_long)Z_STRLEN_P(container); } - if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { + if (EXPECTED(lval >= 0) && ZEND_SIZE_T_GT_ZEND_LONG(Z_STRLEN_P(container), lval)) { return 1; } else { return 0; @@ -3350,7 +3359,7 @@ static zend_never_inline bool ZEND_FASTCALL zend_isempty_dim_slow(const zval *co if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ lval += (zend_long)Z_STRLEN_P(container); } - if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { + if (EXPECTED(lval >= 0) && ZEND_SIZE_T_GT_ZEND_LONG(Z_STRLEN_P(container), lval)) { return (Z_STRVAL_P(container)[lval] == '0'); } else { return 1; diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index c67a31fd8de2..cf105732160a 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1245,7 +1245,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * ALLOC_HASHTABLE(CG(unlinked_uses)); zend_hash_init(CG(unlinked_uses), 0, NULL, NULL, 0); } - zend_hash_index_add_empty_element(CG(unlinked_uses), (zend_ulong)(uintptr_t)ce); + zend_hash_index_add_empty_element(CG(unlinked_uses), ZEND_PTR_TO_ZEND_ULONG(ce)); return ce; } return NULL; diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index b9c77e4f0f6a..d1e61130774c 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -178,7 +178,7 @@ static void zend_generator_remove_child(zend_generator_node *node, zend_generato node->child.single = NULL; } else { HashTable *ht = node->child.ht; - zend_hash_index_del(ht, (zend_ulong)(uintptr_t) child); + zend_hash_index_del(ht, ZEND_PTR_TO_ZEND_ULONG(child)); if (node->children == 2) { zend_generator *other_child; ZEND_HASH_FOREACH_PTR(ht, other_child) { @@ -553,11 +553,11 @@ static void zend_generator_add_child(zend_generator *generator, zend_generator * HashTable *ht = emalloc(sizeof(HashTable)); zend_hash_init(ht, 0, NULL, NULL, 0); zend_hash_index_add_new_ptr(ht, - (zend_ulong) node->child.single, node->child.single); + ZEND_PTR_TO_ZEND_ULONG(node->child.single), node->child.single); node->child.ht = ht; } - zend_hash_index_add_new_ptr(node->child.ht, (zend_ulong)(uintptr_t) child, child); + zend_hash_index_add_new_ptr(node->child.ht, ZEND_PTR_TO_ZEND_ULONG(child), child); } ++node->children; diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 4424c9a1a3ab..5af5f6980a9d 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -3372,7 +3372,7 @@ static void check_unrecoverable_load_failure(const zend_class_entry *ce) { * a dependence on the inheritance hierarchy of this specific class. Instead we fall back to * a fatal error, as would happen if we did not allow exceptions in the first place. */ if (CG(unlinked_uses) - && zend_hash_index_del(CG(unlinked_uses), (zend_ulong)(uintptr_t)ce) == SUCCESS) { + && zend_hash_index_del(CG(unlinked_uses), ZEND_PTR_TO_ZEND_ULONG(ce)) == SUCCESS) { zend_exception_uncaught_error( "During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name)); } @@ -3667,7 +3667,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string } if (CG(unlinked_uses)) { - zend_hash_index_del(CG(unlinked_uses), (zend_ulong)(uintptr_t) ce); + zend_hash_index_del(CG(unlinked_uses), ZEND_PTR_TO_ZEND_ULONG(ce)); } orig_linking_class = CG(current_linking_class); diff --git a/Zend/zend_long.h b/Zend/zend_long.h index 303bacd03d4c..8dcb6ebe8047 100644 --- a/Zend/zend_long.h +++ b/Zend/zend_long.h @@ -22,7 +22,7 @@ #include /* This is the heart of the whole int64 enablement in zval. */ -#if defined(__x86_64__) || defined(__LP64__) || defined(_LP64) || defined(_WIN64) +#ifdef ZEND_INT64 # define ZEND_ENABLE_ZVAL_LONG64 1 #endif diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 8ca6d212fd72..aa3757a184ea 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -450,7 +450,7 @@ static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *c *info_ptr = property_info; } if (cache_slot) { - CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, (void*)(uintptr_t)offset); + CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, (void*) offset); CACHE_PTR_EX(cache_slot + 2, property_info); } return offset; diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 153a6cea6b43..0a79ffc5b5ac 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -538,7 +538,9 @@ ZEND_API void zend_reset_lc_ctype_locale(void); static zend_always_inline void fast_long_increment_function(zval *op1) { -#if ZEND_USE_ASM_ARITHMETIC && defined(__i386__) && !(4 == __GNUC__ && 8 == __GNUC_MINOR__) +#if ZEND_USE_ASM_ARITHMETIC && defined(__i386__) \ + && (SIZEOF_ZEND_LONG == 4 || SIZEOF_ZEND_LONG == 8) && !(4 == __GNUC__ && 8 == __GNUC_MINOR__) +# if SIZEOF_ZEND_LONG == 4 __asm__ goto( "addl $1,(%0)\n\t" "jo %l1\n" @@ -546,6 +548,16 @@ static zend_always_inline void fast_long_increment_function(zval *op1) : "r"(&op1->value) : "cc", "memory" : overflow); +# else + __asm__ goto( + "addl $1,(%0)\n\t" + "adcl $0,4(%0)\n\t" + "jo %l1\n" + : + : "r"(&op1->value) + : "cc", "memory" + : overflow); +# endif return; overflow: ZEND_ATTRIBUTE_COLD_LABEL ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0); @@ -617,7 +629,9 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL static zend_always_inline void fast_long_decrement_function(zval *op1) { -#if ZEND_USE_ASM_ARITHMETIC && defined(__i386__) && !(4 == __GNUC__ && 8 == __GNUC_MINOR__) +#if ZEND_USE_ASM_ARITHMETIC && defined(__i386__) \ + && (SIZEOF_ZEND_LONG == 4 || SIZEOF_ZEND_LONG == 8) && !(4 == __GNUC__ && 8 == __GNUC_MINOR__) +# if SIZEOF_ZEND_LONG == 4 __asm__ goto( "subl $1,(%0)\n\t" "jo %l1\n" @@ -625,6 +639,16 @@ static zend_always_inline void fast_long_decrement_function(zval *op1) : "r"(&op1->value) : "cc", "memory" : overflow); +# else + __asm__ goto( + "subl $1,(%0)\n\t" + "sbbl $0,4(%0)\n\t" + "jo %l1\n" + : + : "r"(&op1->value) + : "cc", "memory" + : overflow); +# endif return; overflow: ZEND_ATTRIBUTE_COLD_LABEL ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0); @@ -696,7 +720,14 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL static zend_always_inline void fast_long_add_function(zval *result, zval *op1, zval *op2) { -#if ZEND_USE_ASM_ARITHMETIC && defined(__i386__) && !(4 == __GNUC__ && 8 == __GNUC_MINOR__) +/* There is no SIZEOF_ZEND_LONG == 8 counterpart to the i386 sequence below: + * holding a 64-bit value takes two scratch registers, and inside execute_ex() + * %esi and %edi are pinned as the VM's global register variables, leaving only + * eax/ebx/ecx/edx. Three "r" operands plus two clobbers cannot be satisfied, + * and gcc loops in register allocation instead of reporting it. That + * configuration is served by the __builtin_s{add,sub}ll_overflow() paths + * further down. */ +#if ZEND_USE_ASM_ARITHMETIC && defined(__i386__) && SIZEOF_ZEND_LONG == 4 && !(4 == __GNUC__ && 8 == __GNUC_MINOR__) __asm__ goto( "movl (%1), %%eax\n\t" "addl (%2), %%eax\n\t" @@ -800,7 +831,14 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL static zend_always_inline void fast_long_sub_function(zval *result, zval *op1, zval *op2) { -#if ZEND_USE_ASM_ARITHMETIC && defined(__i386__) && !(4 == __GNUC__ && 8 == __GNUC_MINOR__) +/* There is no SIZEOF_ZEND_LONG == 8 counterpart to the i386 sequence below: + * holding a 64-bit value takes two scratch registers, and inside execute_ex() + * %esi and %edi are pinned as the VM's global register variables, leaving only + * eax/ebx/ecx/edx. Three "r" operands plus two clobbers cannot be satisfied, + * and gcc loops in register allocation instead of reporting it. That + * configuration is served by the __builtin_s{add,sub}ll_overflow() paths + * further down. */ +#if ZEND_USE_ASM_ARITHMETIC && defined(__i386__) && SIZEOF_ZEND_LONG == 4 && !(4 == __GNUC__ && 8 == __GNUC_MINOR__) __asm__ goto( "movl (%1), %%eax\n\t" "subl (%2), %%eax\n\t" diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index ccad24682fdb..36d3dd15d7c0 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -945,4 +945,33 @@ static zend_always_inline uint64_t ZEND_BYTES_SWAP64(uint64_t u) # define ZEND_OPCACHE_SHM_REATTACHMENT 1 #endif +/* A pointer always fits a zend_long on the supported platforms, + * so that direction is a plain cast. The reverse only narrows where zend_long is + * wider than a pointer, which is exactly what ZEND_INT64 on a 32bit platform + * does; the checks are compiled in only there, and only carry code in a debug + * build. Outside one ZEND_ASSERT() becomes ZEND_ASSUME(), which lets the + * optimizer drop the branch and reduce the call to the same plain cast. */ +#define ZEND_PTR_TO_ZEND_LONG(ptr) ((zend_long) (intptr_t) (ptr)) +#define ZEND_PTR_TO_ZEND_ULONG(ptr) ((zend_ulong) (uintptr_t) (ptr)) + +#if SIZEOF_SIZE_T < SIZEOF_ZEND_LONG +static zend_always_inline void* _zend_long_to_ptr(zend_long zlong) +{ + ZEND_ASSERT(zlong >= (zend_long) INTPTR_MIN && zlong <= (zend_long) INTPTR_MAX); + return (void *) (intptr_t) zlong; +} + +static zend_always_inline void* _zend_ulong_to_ptr(zend_ulong ulong) +{ + ZEND_ASSERT(ulong <= (zend_ulong) UINTPTR_MAX); + return (void *) (uintptr_t) ulong; +} + +# define ZEND_LONG_TO_PTR(zlong) _zend_long_to_ptr(zlong) +# define ZEND_ULONG_TO_PTR(ulong) _zend_ulong_to_ptr(ulong) +#else +# define ZEND_LONG_TO_PTR(zlong) ((void *) (intptr_t) (zlong)) +# define ZEND_ULONG_TO_PTR(ulong) ((void *) (uintptr_t) (ulong)) +#endif + #endif /* ZEND_PORTABILITY_H */ diff --git a/Zend/zend_range_check.h b/Zend/zend_range_check.h index 8db867434399..0f9b67d61470 100644 --- a/Zend/zend_range_check.h +++ b/Zend/zend_range_check.h @@ -29,9 +29,7 @@ #endif #if SIZEOF_INT < SIZEOF_SIZE_T -/* size_t can always overflow signed int on the same platform. - Furthermore, by the current design, size_t can always - overflow zend_long. */ +/* size_t can always overflow signed int on the same platform. */ # define ZEND_SIZE_T_CAN_OVFL_UINT 1 #endif @@ -57,10 +55,40 @@ # define ZEND_SIZE_T_UINT_OVFL(size) (0) #endif -/* Comparison zend_long vs size_t */ -#define ZEND_SIZE_T_GT_ZEND_LONG(size, zlong) ((zlong) < 0 || (size) > (size_t)(zlong)) -#define ZEND_SIZE_T_GTE_ZEND_LONG(size, zlong) ((zlong) < 0 || (size) >= (size_t)(zlong)) -#define ZEND_SIZE_T_LT_ZEND_LONG(size, zlong) ((zlong) >= 0 && (size) < (size_t)(zlong)) -#define ZEND_SIZE_T_LTE_ZEND_LONG(size, zlong) ((zlong) >= 0 && (size) <= (size_t)(zlong)) +/* zend_long vs size_t checks. */ +#if SIZEOF_SIZE_T < SIZEOF_ZEND_LONG +# define ZEND_SIZE_T_ZEND_LONG_OVFL(size) (0) +# define ZEND_LONG_SIZE_T_OVFL(zlong) UNEXPECTED((zlong) > (zend_long)SIZE_MAX) + +# define ZEND_SIZE_T_GT_ZEND_LONG(size, zlong) ((zlong) < 0 || ((zlong) < SIZE_MAX && (size) > (size_t)(zlong))) +# define ZEND_SIZE_T_GT_ZEND_ULONG(size, zulong) ((zulong) < SIZE_MAX && (size) > (size_t)(zulong)) +# define ZEND_SIZE_T_GTE_ZEND_LONG(size, zlong) ((zlong) < 0 || ((zlong) <= SIZE_MAX && (size) >= (size_t)(zlong))) +# define ZEND_SIZE_T_GTE_ZEND_ULONG(size, zulong) ((zulong) <= SIZE_MAX && (size) >= (size_t)(zulong)) +# define ZEND_SIZE_T_LT_ZEND_LONG(size, zlong) ((zlong) > SIZE_MAX || ((zlong) > 0 && (size) < (size_t)(zlong))) +# define ZEND_SIZE_T_LT_ZEND_ULONG(size, zulong) ((zulong) > SIZE_MAX || (size) < (size_t)(zulong)) +# define ZEND_SIZE_T_LTE_ZEND_LONG(size, zlong) ((zlong) > SIZE_MAX || ((zlong) >= 0 && (size) <= (size_t)(zlong))) +# define ZEND_SIZE_T_LTE_ZEND_ULONG(size, zulong) ((zulong) > SIZE_MAX || (size) <= (size_t)(zulong)) +#else +# define ZEND_SIZE_T_ZEND_LONG_OVFL(size) UNEXPECTED((size) > (size_t)ZEND_LONG_MAX) +# define ZEND_LONG_SIZE_T_OVFL(zlong) (0) + +# define ZEND_SIZE_T_GT_ZEND_LONG(size, zlong) ((zlong) < 0 || (size) > (size_t)(zlong)) +# define ZEND_SIZE_T_GT_ZEND_ULONG(size, zulong) ((size) > (size_t)(zulong)) +# define ZEND_SIZE_T_GTE_ZEND_LONG(size, zlong) ((zlong) < 0 || (size) >= (size_t)(zlong)) +# define ZEND_SIZE_T_GTE_ZEND_ULONG(size, zulong) ((size) >= (size_t)(zulong)) +# define ZEND_SIZE_T_LT_ZEND_LONG(size, zlong) ((zlong) > 0 && (size) < (size_t)(zlong)) +# define ZEND_SIZE_T_LT_ZEND_ULONG(size, zulong) ((size) < (size_t)(zulong)) +# define ZEND_SIZE_T_LTE_ZEND_LONG(size, zlong) ((zlong) >= 0 && (size) <= (size_t)(zlong)) +# define ZEND_SIZE_T_LTE_ZEND_ULONG(size, zulong) ((size) <= (size_t)(zulong)) +#endif + +# define ZEND_LONG_GT_SIZE_T(zlong, size) ZEND_SIZE_T_LT_ZEND_LONG(size, zlong) +# define ZEND_ULONG_GT_SIZE_T(zulong, size) ZEND_SIZE_T_LT_ZEND_ULONG(size, zulong) +# define ZEND_LONG_GTE_SIZE_T(zlong, size) ZEND_SIZE_T_LTE_ZEND_LONG(size, zlong) +# define ZEND_ULONG_GTE_SIZE_T(zulong, size) ZEND_SIZE_T_LTE_ZEND_ULONG(size, zulong) +# define ZEND_LONG_LT_SIZE_T(zlong, size) ZEND_SIZE_T_GT_ZEND_LONG(size, zlong) +# define ZEND_ULONG_LT_SIZE_T(zulong, size) ZEND_SIZE_T_GT_ZEND_ULONG(size, zulong) +# define ZEND_LONG_LTE_SIZE_T(zlong, size) ZEND_SIZE_T_GTE_ZEND_LONG(size, zlong) +# define ZEND_ULONG_LTE_SIZE_T(zulong, size) ZEND_SIZE_T_GTE_ZEND_ULONG(size, zulong) #endif /* ZEND_RANGE_CHECK_H */ diff --git a/Zend/zend_string.c b/Zend/zend_string.c index b1b4a0e17a69..ea4deac2f536 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -425,7 +425,7 @@ ZEND_API zend_never_inline NOIPA bool ZEND_FASTCALL zend_string_equal_val(const const char *ptr = ZSTR_VAL(s1); uintptr_t delta = (uintptr_t) s2 - (uintptr_t) s1; size_t len = ZSTR_LEN(s1); - zend_ulong ret; + size_t ret; __asm__ ( "0:\n\t" @@ -456,14 +456,13 @@ ZEND_API zend_never_inline NOIPA bool ZEND_FASTCALL zend_string_equal_val(const : "cc"); return ret; } - #elif defined(__GNUC__) && defined(__x86_64__) && !defined(__ILP32__) ZEND_API zend_never_inline NOIPA bool ZEND_FASTCALL zend_string_equal_val(const zend_string *s1, const zend_string *s2) { const char *ptr = ZSTR_VAL(s1); uintptr_t delta = (uintptr_t) s2 - (uintptr_t) s1; size_t len = ZSTR_LEN(s1); - zend_ulong ret; + size_t ret; __asm__ ( "0:\n\t" diff --git a/Zend/zend_string.h b/Zend/zend_string.h index ad66fe168c8e..3789a56a9934 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -130,6 +130,22 @@ static zend_always_inline zend_string *ZSTR_KNOWN(size_t idx) { #define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1)) #define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD) +/* True when a zend_long is too large to be used as a zend_string length. + * zend_string_alloc() and zend_string_safe_alloc() add the header and the + * terminating NUL to the requested length without checking for overflow, so a + * length above ZSTR_MAX_LEN wraps to a tiny allocation carrying a huge + * ZSTR_LEN. Callers must reject negative values separately. + * + * Always false where zend_long is no wider than size_t: a non-negative + * zend_long cannot exceed ZSTR_MAX_LEN there. Note that the same is not true + * of a size_t operand, which is why plain comparisons against ZSTR_MAX_LEN are + * used for those. */ +#if SIZEOF_SIZE_T < SIZEOF_ZEND_LONG +# define ZEND_LONG_ZSTR_LEN_OVFL(zlong) UNEXPECTED((zlong) > (zend_long) ZSTR_MAX_LEN) +#else +# define ZEND_LONG_ZSTR_LEN_OVFL(zlong) (0) +#endif + #define ZSTR_ALLOCA_ALLOC(str, _len, use_heap) do { \ (str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(_len), 8), (use_heap)); \ GC_SET_REFCOUNT(str, 1); \ @@ -187,6 +203,7 @@ static zend_always_inline uint32_t zend_string_delref(zend_string *s) static zend_always_inline zend_string *zend_string_alloc(size_t len, bool persistent) { + ZEND_ASSERT(len <= ZSTR_MAX_LEN); zend_string *ret = (zend_string *)pemalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent); GC_SET_REFCOUNT(ret, 1); @@ -198,6 +215,7 @@ static zend_always_inline zend_string *zend_string_alloc(size_t len, bool persis static zend_always_inline zend_string *zend_string_safe_alloc(size_t n, size_t m, size_t l, bool persistent) { + ZEND_ASSERT(l <= ZSTR_MAX_LEN); zend_string *ret = (zend_string *)safe_pemalloc(n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent); GC_SET_REFCOUNT(ret, 1); @@ -261,6 +279,7 @@ static zend_always_inline zend_string *zend_string_realloc(zend_string *s, size_ { zend_string *ret; + ZEND_ASSERT(len <= ZSTR_MAX_LEN); if (!ZSTR_IS_INTERNED(s)) { if (EXPECTED(GC_REFCOUNT(s) == 1)) { ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent); @@ -282,6 +301,7 @@ static zend_always_inline zend_string *zend_string_extend(zend_string *s, size_t zend_string *ret; ZEND_ASSERT(len >= ZSTR_LEN(s)); + ZEND_ASSERT(len <= ZSTR_MAX_LEN); if (!ZSTR_IS_INTERNED(s)) { if (EXPECTED(GC_REFCOUNT(s) == 1)) { ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent); diff --git a/Zend/zend_types.h b/Zend/zend_types.h index b30f53d7f917..4c8c2fb324b1 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -383,11 +383,13 @@ struct _zend_string { char val[1]; }; -typedef struct _Bucket { +/* ZEND_BIND_* stores byte offsets into arData in opline extended values, with + * flags encoded in the low three bits. */ +typedef ZEND_SET_ALIGNED(8, struct _Bucket { zval val; zend_ulong h; /* hash value (or numeric index) */ zend_string *key; /* string key or NULL for numerics */ -} Bucket; +}) Bucket; typedef struct _zend_array HashTable; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index c0fd2eef277b..ef0223fce80b 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -9853,7 +9853,7 @@ ZEND_VM_HANDLER(202, ZEND_CALLABLE_CONVERT, UNUSED, UNUSED, NUM|CACHE_SLOT) } else { /* Rotate the key for better hash distribution. */ const int shift = sizeof(size_t) == 4 ? 6 : 7; - zend_ulong key = (zend_ulong)(uintptr_t)call->func; + zend_ulong key = ZEND_PTR_TO_ZEND_ULONG(call->func); key = (key >> shift) | (key << ((sizeof(key) * 8) - shift)); zval *closure_zv = zend_hash_index_lookup(&EG(callable_convert_cache), key); if (Z_TYPE_P(closure_zv) == IS_NULL) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index b956b638b7e4..5986d43cd634 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -37662,7 +37662,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_CALLABLE_CONV } else { /* Rotate the key for better hash distribution. */ const int shift = sizeof(size_t) == 4 ? 6 : 7; - zend_ulong key = (zend_ulong)(uintptr_t)call->func; + zend_ulong key = ZEND_PTR_TO_ZEND_ULONG(call->func); key = (key >> shift) | (key << ((sizeof(key) * 8) - shift)); zval *closure_zv = zend_hash_index_lookup(&EG(callable_convert_cache), key); if (Z_TYPE_P(closure_zv) == IS_NULL) { @@ -90305,7 +90305,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_CALLABLE_CONVERT_S } else { /* Rotate the key for better hash distribution. */ const int shift = sizeof(size_t) == 4 ? 6 : 7; - zend_ulong key = (zend_ulong)(uintptr_t)call->func; + zend_ulong key = ZEND_PTR_TO_ZEND_ULONG(call->func); key = (key >> shift) | (key << ((sizeof(key) * 8) - shift)); zval *closure_zv = zend_hash_index_lookup(&EG(callable_convert_cache), key); if (Z_TYPE_P(closure_zv) == IS_NULL) { @@ -123271,7 +123271,7 @@ static void init_opcode_serialiser(void) Z_TYPE_INFO(tmp) = IS_LONG; for (i = 0; i < zend_handlers_count; i++) { Z_LVAL(tmp) = i; - zend_hash_index_add(zend_handlers_table, (zend_ulong)(uintptr_t)zend_opcode_handlers[i], &tmp); + zend_hash_index_add(zend_handlers_table, ZEND_PTR_TO_ZEND_ULONG(zend_opcode_handlers[i]), &tmp); } } @@ -123282,7 +123282,7 @@ ZEND_API void ZEND_FASTCALL zend_serialize_opcode_handler(zend_op *op) if (!zend_handlers_table) { init_opcode_serialiser(); } - zv = zend_hash_index_find(zend_handlers_table, (zend_ulong)(uintptr_t)op->handler); + zv = zend_hash_index_find(zend_handlers_table, ZEND_PTR_TO_ZEND_ULONG(op->handler)); ZEND_ASSERT(zv != NULL); op->handler = (zend_vm_opcode_handler_t)(uintptr_t)Z_LVAL_P(zv); } @@ -123300,7 +123300,7 @@ ZEND_API const void* ZEND_FASTCALL zend_get_opcode_handler_func(const zend_op *o if (!zend_handlers_table) { init_opcode_serialiser(); } - zv = zend_hash_index_find(zend_handlers_table, (zend_ulong)(uintptr_t)op->handler); + zv = zend_hash_index_find(zend_handlers_table, ZEND_PTR_TO_ZEND_ULONG(op->handler)); ZEND_ASSERT(zv != NULL); return zend_opcode_handler_funcs[Z_LVAL_P(zv)]; #elif ZEND_VM_KIND == ZEND_VM_KIND_CALL diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 4e8f28270bae..e0f0bbe5e244 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -114,7 +114,7 @@ static void init_opcode_serialiser(void) Z_TYPE_INFO(tmp) = IS_LONG; for (i = 0; i < zend_handlers_count; i++) { Z_LVAL(tmp) = i; - zend_hash_index_add(zend_handlers_table, (zend_ulong)(uintptr_t)zend_opcode_handlers[i], &tmp); + zend_hash_index_add(zend_handlers_table, ZEND_PTR_TO_ZEND_ULONG(zend_opcode_handlers[i]), &tmp); } } @@ -125,7 +125,7 @@ ZEND_API void ZEND_FASTCALL zend_serialize_opcode_handler(zend_op *op) if (!zend_handlers_table) { init_opcode_serialiser(); } - zv = zend_hash_index_find(zend_handlers_table, (zend_ulong)(uintptr_t)op->handler); + zv = zend_hash_index_find(zend_handlers_table, ZEND_PTR_TO_ZEND_ULONG(op->handler)); ZEND_ASSERT(zv != NULL); op->handler = (zend_vm_opcode_handler_t)(uintptr_t)Z_LVAL_P(zv); } @@ -143,7 +143,7 @@ ZEND_API const void* ZEND_FASTCALL zend_get_opcode_handler_func(const zend_op *o if (!zend_handlers_table) { init_opcode_serialiser(); } - zv = zend_hash_index_find(zend_handlers_table, (zend_ulong)(uintptr_t)op->handler); + zv = zend_hash_index_find(zend_handlers_table, ZEND_PTR_TO_ZEND_ULONG(op->handler)); ZEND_ASSERT(zv != NULL); return zend_opcode_handler_funcs[Z_LVAL_P(zv)]; #elif ZEND_VM_KIND == ZEND_VM_KIND_CALL diff --git a/Zend/zend_vm_trace_map.h b/Zend/zend_vm_trace_map.h index 18c705b454d5..bf0abddcf474 100644 --- a/Zend/zend_vm_trace_map.h +++ b/Zend/zend_vm_trace_map.h @@ -19,7 +19,7 @@ #include "zend_sort.h" #define GEN_MAP(n, name) do { \ - ZVAL_LONG(&tmp, (zend_long)(uintptr_t)zend_opcode_handlers[n]); \ + ZVAL_LONG(&tmp, ZEND_PTR_TO_ZEND_ULONG(zend_opcode_handlers[n])); \ zend_hash_str_add(&vm_trace_ht, #name, sizeof(#name) - 1, &tmp); \ } while (0); diff --git a/Zend/zend_weakrefs.c b/Zend/zend_weakrefs.c index ad0308f44e20..5bee3f0838cd 100644 --- a/Zend/zend_weakrefs.c +++ b/Zend/zend_weakrefs.c @@ -107,15 +107,15 @@ static void zend_weakref_register(zend_object *object, void *payload) { void *tagged_ptr = Z_PTR_P(zv); if (ZEND_WEAKREF_GET_TAG(tagged_ptr) == ZEND_WEAKREF_TAG_HT) { HashTable *ht = ZEND_WEAKREF_GET_PTR(tagged_ptr); - zend_hash_index_add_new_ptr(ht, (zend_ulong)(uintptr_t) payload, payload); + zend_hash_index_add_new_ptr(ht, ZEND_PTR_TO_ZEND_ULONG(payload), payload); return; } /* Convert simple pointer to hashtable. */ HashTable *ht = emalloc(sizeof(HashTable)); zend_hash_init(ht, 0, NULL, NULL, 0); - zend_hash_index_add_new_ptr(ht, (zend_ulong)(uintptr_t) tagged_ptr, tagged_ptr); - zend_hash_index_add_new_ptr(ht, (zend_ulong)(uintptr_t) payload, payload); + zend_hash_index_add_new_ptr(ht, ZEND_PTR_TO_ZEND_ULONG(tagged_ptr), tagged_ptr); + zend_hash_index_add_new_ptr(ht, ZEND_PTR_TO_ZEND_ULONG(payload), payload); /* Replace the single WeakMap or WeakReference entry in EG(weakrefs) with a HashTable with 2 entries in place. */ ZVAL_PTR(zv, ZEND_WEAKREF_ENCODE(ht, ZEND_WEAKREF_TAG_HT)); } @@ -144,11 +144,11 @@ static void zend_weakref_unregister(zend_object *object, void *payload, bool wea HashTable *ht = ptr; #if ZEND_DEBUG - void *old_payload = zend_hash_index_find_ptr(ht, (zend_ulong)(uintptr_t) payload); + void *old_payload = zend_hash_index_find_ptr(ht, ZEND_PTR_TO_ZEND_ULONG(payload)); ZEND_ASSERT(old_payload && "Weakref not registered?"); ZEND_ASSERT(old_payload == payload); #endif - zend_hash_index_del(ht, (zend_ulong)(uintptr_t) payload); + zend_hash_index_del(ht, ZEND_PTR_TO_ZEND_ULONG(payload)); if (zend_hash_num_elements(ht) == 0) { GC_DEL_FLAGS(object, IS_OBJ_WEAKLY_REFERENCED); zend_hash_destroy(ht); diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 1795d41b27ce..d49acb6fe23e 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -668,6 +668,18 @@ static const char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib } /* }}} */ +static zend_long date_date_to_zlong(timelib_time *d, int *error) +{ +#if SIZEOF_ZEND_LONG >= SIZEOF_LONG_LONG + if (error) { + *error = 0; + } + return (zend_long) d->sse; +#else + return timelib_date_to_int(d, error); +#endif +} + /* {{{ date_format - (gm)date helper */ static zend_string *date_format(const char *format, size_t format_len, const timelib_time *t, bool localtime) { @@ -881,7 +893,7 @@ static void php_date(INTERNAL_FUNCTION_PARAMETERS, bool localtime) } /* }}} */ -PHPAPI zend_string *php_format_date(const char *format, size_t format_len, time_t ts, bool localtime) /* {{{ */ +PHPAPI zend_string *php_format_date(const char *format, size_t format_len, zend_long ts, bool localtime) /* {{{ */ { timelib_time *t; timelib_tzinfo *tzi; @@ -907,7 +919,7 @@ PHPAPI zend_string *php_format_date(const char *format, size_t format_len, time_ /* }}} */ /* {{{ php_idate */ -PHPAPI bool php_idate(char format, time_t ts, bool localtime, int *result) +PHPAPI bool php_idate(char format, zend_long ts, bool localtime, int *result) { timelib_time *t; timelib_tzinfo *tzi; @@ -1135,7 +1147,7 @@ PHP_FUNCTION(strtotime) timelib_fill_holes(t, now, TIMELIB_NO_CLONE); timelib_update_ts(t, tzi); - ts = timelib_date_to_int(t, &epoch_does_not_fit_in_zend_long); + ts = date_date_to_zlong(t, &epoch_does_not_fit_in_zend_long); timelib_time_dtor(now); timelib_time_dtor(t); @@ -1218,8 +1230,7 @@ PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, bool gmt) } /* Clean up and return */ - ts = timelib_date_to_int(now, &epoch_does_not_fit_in_zend_long); - + ts = date_date_to_zlong(now, &epoch_does_not_fit_in_zend_long); if (epoch_does_not_fit_in_zend_long) { timelib_time_dtor(now); php_error_docref(NULL, E_WARNING, "Epoch doesn't fit in a PHP integer"); @@ -3968,7 +3979,7 @@ PHP_FUNCTION(date_timestamp_get) timelib_update_ts(dateobj->time, NULL); } - timestamp = timelib_date_to_int(dateobj->time, &epoch_does_not_fit_in_zend_long); + timestamp = date_date_to_zlong(dateobj->time, &epoch_does_not_fit_in_zend_long); if (epoch_does_not_fit_in_zend_long) { zend_throw_error(date_ce_date_range_error, "Epoch doesn't fit in a PHP integer"); diff --git a/ext/date/php_date.h b/ext/date/php_date.h index 97a49974f1a4..1cf2fd3fcacd 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -127,12 +127,12 @@ PHPAPI time_t php_time(void); /* Backwards compatibility wrapper */ PHPAPI zend_long php_parse_date(const char *string, zend_long *now); PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, bool gmt); -PHPAPI bool php_idate(char format, time_t ts, bool localtime, int *result); +PHPAPI bool php_idate(char format, zend_long ts, bool localtime, int *result); #define _php_strftime php_strftime PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, bool gm); -PHPAPI zend_string *php_format_date(const char *format, size_t format_len, time_t ts, bool localtime); +PHPAPI zend_string *php_format_date(const char *format, size_t format_len, zend_long ts, bool localtime); PHPAPI zend_string *php_format_date_obj(const char *format, size_t format_len, const php_date_obj *date_obj); /* Mechanism to set new TZ database */ diff --git a/ext/date/tests/idate_64bit.phpt b/ext/date/tests/idate_64bit.phpt new file mode 100644 index 000000000000..07ab742dfc2e --- /dev/null +++ b/ext/date/tests/idate_64bit.phpt @@ -0,0 +1,32 @@ +--TEST-- +idate() with timestamps outside the 32bit range +--SKIPIF-- + +--INI-- +date.timezone=UTC +--FILE-- + +--EXPECT-- + 0: 1970-1-1 0 (date: 1970-1-1 0) + 2147483647: 2038-1-19 3 (date: 2038-1-19 3) + 2147483648: 2038-1-19 3 (date: 2038-1-19 3) + 4102444800: 2100-1-1 0 (date: 2100-1-1 0) + 253402300799: 9999-12-31 23 (date: 9999-12-31 23) + -2147483649: 1901-12-13 20 (date: 1901-12-13 20) diff --git a/ext/dom/namespace_compat.c b/ext/dom/namespace_compat.c index 29a0714c62fc..643f5452f1d7 100644 --- a/ext/dom/namespace_compat.c +++ b/ext/dom/namespace_compat.c @@ -501,7 +501,7 @@ static xmlNsPtr dom_alloc_ns_decl(HashTable *links, xmlNodePtr node) return NULL; } - zval *zv = zend_hash_index_lookup(links, (zend_ulong) node); + zval *zv = zend_hash_index_lookup(links, ZEND_PTR_TO_ZEND_ULONG(node)); if (Z_ISNULL_P(zv)) { ZVAL_LONG(zv, 1); } else { @@ -575,7 +575,7 @@ static void dom_relink_ns_decls_element(HashTable *links, xmlNodePtr node) if (node->ns && !node->ns->prefix) { /* Workaround for the behaviour where the xmlSearchNs() call inside c14n.c * can return the current namespace. */ - zend_hash_index_add_new_ptr(links, (zend_ulong) node | 1, node->ns); + zend_hash_index_add_new_ptr(links, ZEND_PTR_TO_ZEND_ULONG(node) | 1, node->ns); node->ns = xmlSearchNs(node->doc, node, NULL); } else if (node->ns) { dom_add_synthetic_ns_decl(links, node, node->ns); @@ -605,10 +605,10 @@ void dom_unlink_ns_decls(HashTable *links) { ZEND_HASH_MAP_FOREACH_NUM_KEY_VAL(links, zend_ulong h, zval *data) { if (h & 1) { - xmlNodePtr node = (xmlNodePtr) (h ^ 1); + xmlNodePtr node = (xmlNodePtr) ZEND_ULONG_TO_PTR(h ^ 1); node->ns = Z_PTR_P(data); } else { - xmlNodePtr node = (xmlNodePtr) h; + xmlNodePtr node = (xmlNodePtr) ZEND_ULONG_TO_PTR(h); while (Z_LVAL_P(data)-- > 0) { xmlNsPtr ns = node->nsDef; node->nsDef = ns->next; diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 4a81026d451b..d2ddef034a4d 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -104,6 +104,68 @@ PHP_GMP_API zend_class_entry *php_gmp_class_entry(void) { #define GET_GMP_FROM_ZVAL(zval) \ GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zval))->num +#define GMP_SI_MAX (GMP_NUMB_MAX >> 1) +#define GMP_SI_MIN (-(1LL << (GMP_NUMB_BITS - 1))) +#if GMP_NUMB_BITS < SIZEOF_ZEND_LONG*8 +static void gmp_set_zlong(mpz_t z, zend_long zlong) { + if (zlong <= GMP_SI_MAX && zlong >= GMP_SI_MIN) { + mpz_set_si(z, zlong); + } else { + /* mpz_import() takes no sign from the data, so the magnitude has to be + * formed first. Negating in unsigned arithmetic keeps ZEND_LONG_MIN + * well defined. */ + zend_ulong magnitude = zlong >= 0 ? (zend_ulong) zlong : -(zend_ulong) zlong; + + mpz_import(z, 1, 1, sizeof(magnitude), 0, 0, &magnitude); + if (zlong < 0) { + mpz_neg(z, z); + } + } +} + +static int gmp_fits_zlong_p(mpz_t z) { + int result = 1; + mpz_t min_max; + + if (mpz_cmp_si(z, GMP_SI_MAX) > 0) { + mpz_init(min_max); + gmp_set_zlong(min_max, ZEND_LONG_MAX); + result = mpz_cmp(z, min_max) <= 0; + mpz_clear(min_max); + } else if (mpz_cmp_si(z, GMP_SI_MIN) < 0) { + mpz_init(min_max); + gmp_set_zlong(min_max, ZEND_LONG_MIN); + result = mpz_cmp(z, min_max) >= 0; + mpz_clear(min_max); + } + + return result; +} + +static zend_long gmp_get_zlong(mpz_t z) { + zend_ulong result = 0; + mpz_t z_tmp; + + if (mpz_cmp_si(z, GMP_SI_MAX) <= 0 && mpz_cmp_si(z, GMP_SI_MIN) >= 0) { + return mpz_get_si(z); + } + + mpz_init(z_tmp); + /* The floored remainder is never negative, so this is the two's complement + * image of the low SIZEOF_ZEND_LONG * 8 bits. mpz_export() writes nothing + * at all when that is zero, hence the initialisation of result above. */ + mpz_fdiv_r_2exp(z_tmp, z, SIZEOF_ZEND_LONG * 8); + mpz_export(&result, NULL, 1, sizeof(result), 0, 0, z_tmp); + mpz_clear(z_tmp); + + return (zend_long) result; +} +#else +# define gmp_set_zlong(z, l) mpz_set_si(z, l) +# define gmp_fits_zlong_p(z) mpz_fits_si_p(z) +# define gmp_get_zlong(z) mpz_get_si(z) +#endif + static void gmp_strval(zval *result, mpz_t gmpnum, int base); static zend_result convert_zstr_to_gmp(mpz_t gmp_number, const zend_string *val, zend_long base, uint32_t arg_pos); @@ -127,7 +189,7 @@ static bool gmp_zend_parse_arg_into_mpz_ex( } if (Z_TYPE_P(arg) == IS_LONG) { - mpz_set_si(*destination_mpz_ptr, Z_LVAL_P(arg)); + gmp_set_zlong(*destination_mpz_ptr, Z_LVAL_P(arg)); return true; } @@ -143,7 +205,7 @@ static bool gmp_zend_parse_arg_into_mpz_ex( return false; } - mpz_set_si(*destination_mpz_ptr, lval); + gmp_set_zlong(*destination_mpz_ptr, lval); return true; } @@ -241,7 +303,7 @@ static zend_result gmp_cast_object(zend_object *readobj, zval *writeobj, int typ return SUCCESS; case IS_LONG: gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num; - ZVAL_LONG(writeobj, mpz_get_si(gmpnum)); + ZVAL_LONG(writeobj, gmp_get_zlong(gmpnum)); return SUCCESS; case IS_DOUBLE: gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num; @@ -249,8 +311,8 @@ static zend_result gmp_cast_object(zend_object *readobj, zval *writeobj, int typ return SUCCESS; case _IS_NUMBER: gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num; - if (mpz_fits_si_p(gmpnum)) { - ZVAL_LONG(writeobj, mpz_get_si(gmpnum)); + if (gmp_fits_zlong_p(gmpnum)) { + ZVAL_LONG(writeobj, gmp_get_zlong(gmpnum)); } else { ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum)); } @@ -732,7 +794,7 @@ static zend_result gmp_initialize_number(mpz_ptr gmp_number, const zend_string * return convert_zstr_to_gmp(gmp_number, arg_str, base, 1); } - mpz_set_si(gmp_number, arg_l); + gmp_set_zlong(gmp_number, arg_l); return SUCCESS; } @@ -882,7 +944,7 @@ ZEND_FUNCTION(gmp_intval) GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum) ZEND_PARSE_PARAMETERS_END(); - RETVAL_LONG(mpz_get_si(gmpnum)); + RETVAL_LONG(gmp_get_zlong(gmpnum)); } /* }}} */ @@ -1610,8 +1672,13 @@ ZEND_FUNCTION(gmp_random_range) } /* }}} */ +#if SIZEOF_SIZE_T >= SIZEOF_ZEND_LONG +# define GMP_SAFE_BITINDEX_MAX ((mp_bitcnt_t)INT_MAX * GMP_NUMB_BITS) +#else +# define GMP_SAFE_BITINDEX_MAX ((mp_bitcnt_t)INT_MAX * GMP_NUMB_BITS - 1) +#endif static bool gmp_is_bit_index_valid(zend_long index) { - return index >= 0 && (index / GMP_NUMB_BITS < INT_MAX); + return index >= 0 && (zend_ulong)index <= GMP_SAFE_BITINDEX_MAX; } /* {{{ Sets or clear bit in a */ @@ -1627,7 +1694,7 @@ ZEND_FUNCTION(gmp_setbit) } if (!gmp_is_bit_index_valid(index)) { - zend_argument_value_error(2, "must be between 0 and %d * %d", INT_MAX, GMP_NUMB_BITS); + zend_argument_value_error(2, "must be between 0 and %lu", GMP_SAFE_BITINDEX_MAX); RETURN_THROWS(); } @@ -1653,7 +1720,7 @@ ZEND_FUNCTION(gmp_clrbit) } if (!gmp_is_bit_index_valid(index)) { - zend_argument_value_error(2, "must be between 0 and %d * %d", INT_MAX, GMP_NUMB_BITS); + zend_argument_value_error(2, "must be between 0 and %lu", GMP_SAFE_BITINDEX_MAX); RETURN_THROWS(); } @@ -1674,7 +1741,7 @@ ZEND_FUNCTION(gmp_testbit) ZEND_PARSE_PARAMETERS_END(); if (!gmp_is_bit_index_valid(index)) { - zend_argument_value_error(2, "must be between 0 and %d * %d", INT_MAX, GMP_NUMB_BITS); + zend_argument_value_error(2, "must be between 0 and %lu", GMP_SAFE_BITINDEX_MAX); RETURN_THROWS(); } @@ -1686,12 +1753,21 @@ ZEND_FUNCTION(gmp_testbit) ZEND_FUNCTION(gmp_popcount) { mpz_ptr gmpnum_a; + mp_bitcnt_t result; ZEND_PARSE_PARAMETERS_START(1, 1) GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) ZEND_PARSE_PARAMETERS_END(); - RETURN_LONG(mpz_popcount(gmpnum_a)); + result = mpz_popcount(gmpnum_a); + +#if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG + if (SIZE_MAX == result) { + RETURN_LONG(-1); + } +#endif + + RETURN_LONG(result); } /* }}} */ @@ -1699,13 +1775,22 @@ ZEND_FUNCTION(gmp_popcount) ZEND_FUNCTION(gmp_hamdist) { mpz_ptr gmpnum_a, gmpnum_b; + mp_bitcnt_t result; ZEND_PARSE_PARAMETERS_START(2, 2) GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_b) ZEND_PARSE_PARAMETERS_END(); - RETURN_LONG(mpz_hamdist(gmpnum_a, gmpnum_b)); + result = mpz_hamdist(gmpnum_a, gmpnum_b); + +#if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG + if (SIZE_MAX == result) { + RETURN_LONG(-1); + } +#endif + + RETURN_LONG(result); } /* }}} */ @@ -1714,6 +1799,7 @@ ZEND_FUNCTION(gmp_scan0) { mpz_ptr gmpnum_a; zend_long start; + mp_bitcnt_t result; ZEND_PARSE_PARAMETERS_START(2, 2) GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) @@ -1721,11 +1807,19 @@ ZEND_FUNCTION(gmp_scan0) ZEND_PARSE_PARAMETERS_END(); if (!gmp_is_bit_index_valid(start)) { - zend_argument_value_error(2, "must be between 0 and %d * %d", INT_MAX, GMP_NUMB_BITS); + zend_argument_value_error(2, "must be between 0 and %lu", GMP_SAFE_BITINDEX_MAX); RETURN_THROWS(); } - RETURN_LONG(mpz_scan0(gmpnum_a, start)); + result = mpz_scan0(gmpnum_a, start); + +#if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG + if (SIZE_MAX == result) { + RETURN_LONG(-1); + } +#endif + + RETURN_LONG(result); } /* }}} */ @@ -1734,6 +1828,8 @@ ZEND_FUNCTION(gmp_scan1) { mpz_ptr gmpnum_a; zend_long start; + mp_bitcnt_t result; + ZEND_PARSE_PARAMETERS_START(2, 2) GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) @@ -1741,11 +1837,19 @@ ZEND_FUNCTION(gmp_scan1) ZEND_PARSE_PARAMETERS_END(); if (!gmp_is_bit_index_valid(start)) { - zend_argument_value_error(2, "must be between 0 and %d * %d", INT_MAX, GMP_NUMB_BITS); + zend_argument_value_error(2, "must be between 0 and %lu", GMP_SAFE_BITINDEX_MAX); RETURN_THROWS(); } - RETURN_LONG(mpz_scan1(gmpnum_a, start)); + result = mpz_scan1(gmpnum_a, start); + +#if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG + if (SIZE_MAX == result) { + RETURN_LONG(-1); + } +#endif + + RETURN_LONG(result); } /* }}} */ diff --git a/ext/gmp/tests/construct_32bit.phpt b/ext/gmp/tests/construct_32bit.phpt new file mode 100644 index 000000000000..581d1d5b3eba --- /dev/null +++ b/ext/gmp/tests/construct_32bit.phpt @@ -0,0 +1,36 @@ +--TEST-- +Constructor for GMP on 32bit int +--SKIPIF-- + +--EXTENSIONS-- +gmp +--FILE-- + + string(10) "2147483647" +} +object(GMP)#1 (1) { + ["num"]=> + string(10) "2147483647" +} +object(GMP)#1 (1) { + ["num"]=> + string(10) "2147483647" +} +object(GMP)#1 (1) { + ["num"]=> + string(11) "-2147483648" +} +object(GMP)#1 (1) { + ["num"]=> + string(11) "-2147483648" +} diff --git a/ext/gmp/tests/construct_64bit.phpt b/ext/gmp/tests/construct_64bit.phpt new file mode 100644 index 000000000000..3da2eb50f4a6 --- /dev/null +++ b/ext/gmp/tests/construct_64bit.phpt @@ -0,0 +1,55 @@ +--TEST-- +Constructor for GMP on 64bit int +--SKIPIF-- + +--EXTENSIONS-- +gmp +--FILE-- + + string(19) "9223372036854775807" +} +object(GMP)#1 (1) { + ["num"]=> + string(19) "9223372036854775807" +} +object(GMP)#1 (1) { + ["num"]=> + string(19) "9223372036854775807" +} +object(GMP)#1 (1) { + ["num"]=> + string(20) "-9223372036854775808" +} +object(GMP)#1 (1) { + ["num"]=> + string(20) "-9223372036854775808" +} +object(GMP)#1 (1) { + ["num"]=> + string(10) "2147483648" +} +object(GMP)#1 (1) { + ["num"]=> + string(11) "-2147483649" +} +object(GMP)#1 (1) { + ["num"]=> + string(11) "-3000000000" +} diff --git a/ext/gmp/tests/gmp_clrbit.phpt b/ext/gmp/tests/gmp_clrbit.phpt index 9dc63a87f5a5..f95964d1fc88 100644 --- a/ext/gmp/tests/gmp_clrbit.phpt +++ b/ext/gmp/tests/gmp_clrbit.phpt @@ -46,9 +46,9 @@ echo "Done\n"; ?> --EXPECTF-- string(1) "0" -ValueError: gmp_clrbit(): Argument #2 ($index) must be between 0 and %d * %d +ValueError: gmp_clrbit(): Argument #2 ($index) must be between 0 and %d string(2) "-1" -ValueError: gmp_clrbit(): Argument #2 ($index) must be between 0 and %d * %d +ValueError: gmp_clrbit(): Argument #2 ($index) must be between 0 and %d string(7) "1000000" string(7) "1000000" string(30) "238462734628347239571822592658" diff --git a/ext/gmp/tests/gmp_intval_64bit.phpt b/ext/gmp/tests/gmp_intval_64bit.phpt new file mode 100644 index 000000000000..555fad6c34a6 --- /dev/null +++ b/ext/gmp/tests/gmp_intval_64bit.phpt @@ -0,0 +1,61 @@ +--TEST-- +gmp_intval() on 64bit int +--SKIPIF-- + +--EXTENSIONS-- +gmp +--FILE-- + gmp_pow(2, 64), + '2 ** 65' => gmp_pow(2, 65), + '2 ** 128' => gmp_pow(2, 128), + '2 ** 64 + 1' => gmp_add(gmp_pow(2, 64), 1), +]; + +foreach ($fixtures as $label => $num) { + echo "$label: "; + var_dump(gmp_intval($num)); +} +?> +--EXPECT-- +2147483647: 2147483647 2147483647 +-2147483648: -2147483648 -2147483648 +2147483648: 2147483648 2147483648 +-2147483649: -2147483649 -2147483649 +3000000000: 3000000000 3000000000 +-3000000000: -3000000000 -3000000000 +4294967295: 4294967295 4294967295 +-4294967296: -4294967296 -4294967296 +9223372036854775807: 9223372036854775807 9223372036854775807 +-9223372036854775808: -9223372036854775808 -9223372036854775808 + +2 ** 64: int(0) +2 ** 65: int(0) +2 ** 128: int(0) +2 ** 64 + 1: int(1) diff --git a/ext/gmp/tests/gmp_popcount.phpt b/ext/gmp/tests/gmp_popcount.phpt index 3b15a659c5ed..b2e8beb5e9cf 100644 --- a/ext/gmp/tests/gmp_popcount.phpt +++ b/ext/gmp/tests/gmp_popcount.phpt @@ -4,7 +4,6 @@ gmp_popcount() basic tests gmp --FILE-- --EXPECTF-- -ValueError: gmp_scan0(): Argument #2 ($start) must be between 0 and %d * %d +ValueError: gmp_scan0(): Argument #2 ($start) must be between 0 and %d int(2) int(0) int(5) diff --git a/ext/gmp/tests/gmp_scan1.phpt b/ext/gmp/tests/gmp_scan1.phpt index 83a70bcba263..f5b6bb7ecf60 100644 --- a/ext/gmp/tests/gmp_scan1.phpt +++ b/ext/gmp/tests/gmp_scan1.phpt @@ -28,7 +28,7 @@ try { echo "Done\n"; ?> --EXPECTF-- -ValueError: gmp_scan1(): Argument #2 ($start) must be between 0 and %d * %d +ValueError: gmp_scan1(): Argument #2 ($start) must be between 0 and %d int(1) int(12) int(9) diff --git a/ext/gmp/tests/gmp_setbit.phpt b/ext/gmp/tests/gmp_setbit.phpt index 09ce16ada7fe..8c50d8be6d4a 100644 --- a/ext/gmp/tests/gmp_setbit.phpt +++ b/ext/gmp/tests/gmp_setbit.phpt @@ -52,7 +52,7 @@ echo "Done\n"; ?> --EXPECTF-- string(2) "-1" -ValueError: gmp_setbit(): Argument #2 ($index) must be between 0 and %d * %d +ValueError: gmp_setbit(): Argument #2 ($index) must be between 0 and %d string(1) "5" string(1) "1" string(1) "7" diff --git a/ext/gmp/tests/gmp_setbit_long.phpt b/ext/gmp/tests/gmp_setbit_long.phpt index e6d2dc262d59..909f7ee58bf8 100644 --- a/ext/gmp/tests/gmp_setbit_long.phpt +++ b/ext/gmp/tests/gmp_setbit_long.phpt @@ -3,7 +3,7 @@ gmp_setbit() with large index --EXTENSIONS-- gmp --SKIPIF-- - + 0 && $a < 0x8000000000; $a <<= 2) { $i = $a - 1; printf("%X\n", $i); @@ -41,5 +42,5 @@ FFFFFFFF 3FFFFFFFF FFFFFFFFF 3FFFFFFFFF -ValueError: gmp_setbit(): Argument #2 ($index) must be between 0 and %d * %d +ValueError: gmp_setbit(): Argument #2 ($index) must be between 0 and %d Done diff --git a/ext/gmp/tests/gmp_testbit.phpt b/ext/gmp/tests/gmp_testbit.phpt index fb6497df5463..d291b3d2afb1 100644 --- a/ext/gmp/tests/gmp_testbit.phpt +++ b/ext/gmp/tests/gmp_testbit.phpt @@ -48,12 +48,12 @@ var_dump(gmp_strval($n)); echo "Done\n"; ?> --EXPECTF-- -ValueError: gmp_testbit(): Argument #2 ($index) must be between 0 and %d * %d +ValueError: gmp_testbit(): Argument #2 ($index) must be between 0 and %d bool(false) bool(false) bool(false) bool(true) -ValueError: gmp_testbit(): Argument #2 ($index) must be between 0 and %d * %d +ValueError: gmp_testbit(): Argument #2 ($index) must be between 0 and %d bool(false) bool(true) string(7) "1000002" diff --git a/ext/mysqlnd/mysqlnd_portability.h b/ext/mysqlnd/mysqlnd_portability.h index 20dfe3429edf..b41ccf355af8 100644 --- a/ext/mysqlnd/mysqlnd_portability.h +++ b/ext/mysqlnd/mysqlnd_portability.h @@ -118,13 +118,13 @@ This file is public domain and comes with NO WARRANTY of any kind */ (((uint32_t) (zend_uchar) (A)[2]) << 16) |\ (((uint32_t) (zend_uchar) (A)[1]) << 8) | \ ((uint32_t) (zend_uchar) (A)[0]))) -#define sint4korr(A) (*((zend_long *) (A))) +#define sint4korr(A) (*((int32_t *) (A))) #define uint2korr(A) (*((uint16_t *) (A))) #define uint3korr(A) (uint32_t) (((uint32_t) ((zend_uchar) (A)[0])) +\ (((uint32_t) ((zend_uchar) (A)[1])) << 8) +\ (((uint32_t) ((zend_uchar) (A)[2])) << 16)) -#define uint4korr(A) (*((zend_ulong *) (A))) +#define uint4korr(A) (*((uint32_t *) (A))) @@ -135,7 +135,7 @@ This file is public domain and comes with NO WARRANTY of any kind */ *(T)= (zend_uchar) ((A));\ *(T+1)=(zend_uchar) (((uint32_t) (A) >> 8));\ *(T+2)=(zend_uchar) (((A) >> 16)); } -#define int4store(T,A) *((zend_long *) (T))= (zend_long) (A) +#define int4store(T,A) *((uint32_t *) (T))= (uint32_t) (A) #define int5store(T,A) { \ *((zend_uchar *)(T))= (zend_uchar)((A));\ *(((zend_uchar *)(T))+1)=(zend_uchar) (((A) >> 8));\ @@ -147,12 +147,12 @@ This file is public domain and comes with NO WARRANTY of any kind */ typedef union { double v; - zend_long m[2]; + int32_t m[2]; } float8get_union; -#define float8get(V,M) { ((float8get_union *)&(V))->m[0] = *((zend_long*) (M)); \ - ((float8get_union *)&(V))->m[1] = *(((zend_long*) (M))+1); } -#define float8store(T,V) { *((zend_long *) (T)) = ((float8get_union *)&(V))->m[0]; \ - *(((zend_long *) (T))+1) = ((float8get_union *)&(V))->m[1]; } +#define float8get(V,M) { ((float8get_union *)&(V))->m[0] = *((int32_t*) (M)); \ + ((float8get_union *)&(V))->m[1] = *(((int32_t*) (M))+1); } +#define float8store(T,V) { *((int32_t *) (T)) = ((float8get_union *)&(V))->m[0]; \ + *(((int32_t *) (T))+1) = ((float8get_union *)&(V))->m[1]; } #define float4get(V,M) { *((float *) &(V)) = *((float*) (M)); } /* From Andrey Hristov based on float8get */ #define floatget(V,M) memcpy((char*) &(V),(char*) (M),sizeof(float)) diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index e91da6aeb8d3..fd8529dd415f 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -3745,6 +3745,18 @@ int zend_jit_check_support(void) { int i; +#if SIZEOF_ZEND_LONG > SIZEOF_SIZE_T + /* The IR x86 backend emits 64bit integer instructions only when built for + * X64. With a zend_long wider than the target word the 8 byte cases are + * absent, so an emit falls through to the byte sized instruction and the + * JIT would silently produce wrong code. */ + zend_accel_error(ACCEL_LOG_WARNING, + "JIT is not supported when zend_long is wider than the platform word. JIT disabled."); + JIT_G(enabled) = 0; + JIT_G(on) = 0; + return FAILURE; +#endif + #ifdef ZEND_JIT_USE_APPLE_MAP_JIT if (!pthread_jit_write_protect_supported_np()) { zend_accel_error(ACCEL_LOG_WARNING, diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 660a17c05687..ca76708305e2 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1501,7 +1501,16 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, offset += (zend_long)ZSTR_LEN(s); } - if ((size_t)offset >= ZSTR_LEN(s)) { + if (ZEND_LONG_GTE_SIZE_T(offset, ZSTR_LEN(s))) { +#if SIZEOF_SIZE_T < SIZEOF_ZEND_LONG + if (UNEXPECTED(offset >= (zend_long) ZSTR_MAX_LEN)) { + zend_throw_error(NULL, "String size overflow"); + if (result) { + ZVAL_UNDEF(result); + } + return; + } +#endif /* Extend string if needed */ zend_long old_len = ZSTR_LEN(s); ZVAL_NEW_STR(str, zend_string_extend(s, (size_t)offset + 1, 0)); diff --git a/ext/opcache/tests/gh9259_001_32bit.phpt b/ext/opcache/tests/gh9259_001_32bit.phpt new file mode 100644 index 000000000000..767430fec4c0 --- /dev/null +++ b/ext/opcache/tests/gh9259_001_32bit.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug GH-9259 001 (Setting opcache.interned_strings_buffer to a very high value leads to corruption of shm) - 32bit +--EXTENSIONS-- +opcache +--SKIPIF-- + +--INI-- +opcache.interned_strings_buffer=131072 +opcache.log_verbosity_level=2 +opcache.enable_cli=1 +--FILE-- + +--EXPECTF-- +%sWarning opcache.interned_strings_buffer must be less than or equal to 4095, 131072 given%s + +OK diff --git a/ext/opcache/tests/gh9259_001.phpt b/ext/opcache/tests/gh9259_001_64bit.phpt similarity index 74% rename from ext/opcache/tests/gh9259_001.phpt rename to ext/opcache/tests/gh9259_001_64bit.phpt index d98cbfb891d7..f1f5773073e0 100644 --- a/ext/opcache/tests/gh9259_001.phpt +++ b/ext/opcache/tests/gh9259_001_64bit.phpt @@ -1,9 +1,9 @@ --TEST-- -Bug GH-9259 001 (Setting opcache.interned_strings_buffer to a very high value leads to corruption of shm) +Bug GH-9259 001 (Setting opcache.interned_strings_buffer to a very high value leads to corruption of shm) - 64bit --EXTENSIONS-- opcache --SKIPIF-- - + --INI-- opcache.interned_strings_buffer=131072 opcache.log_verbosity_level=2 diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 0b6cabe42015..871fd66109bb 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -267,7 +267,7 @@ static void *zend_file_cache_serialize_interned(zend_string *str, } len = ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(ZSTR_LEN(str))); - ret = (void*)(info->str_size | Z_UL(1)); + ret = (void*)(info->str_size | 1); zend_shared_alloc_register_xlat_entry(str, ret); zend_string *s = (zend_string*)ZCG(mem); diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c index 3d6d2a840c33..79542cd314fc 100644 --- a/ext/opcache/zend_shared_alloc.c +++ b/ext/opcache/zend_shared_alloc.c @@ -417,7 +417,7 @@ static zend_always_inline zend_ulong zend_rotr3(zend_ulong key) int zend_shared_memdup_size(void *source, size_t size) { void *old_p; - zend_ulong key = (zend_ulong)source; + zend_ulong key = (zend_ulong)(uintptr_t)source; key = zend_rotr3(key); if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) != NULL) { @@ -434,7 +434,7 @@ static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, b zend_ulong key; if (get_xlat) { - key = (zend_ulong)source; + key = (zend_ulong)(uintptr_t)source; key = zend_rotr3(key); if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) != NULL) { /* we already duplicated this pointer */ @@ -446,7 +446,7 @@ static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, b memcpy(retval, source, size); if (set_xlat) { if (!get_xlat) { - key = (zend_ulong)source; + key = (zend_ulong)(uintptr_t)source; key = zend_rotr3(key); } zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, retval); @@ -589,7 +589,7 @@ void zend_shared_alloc_restore_xlat_table(uint32_t checkpoint) void zend_shared_alloc_register_xlat_entry(const void *key_pointer, const void *value) { - zend_ulong key = (zend_ulong)key_pointer; + zend_ulong key = (zend_ulong)(uintptr_t)key_pointer; key = zend_rotr3(key); zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, (void*)value); @@ -598,7 +598,7 @@ void zend_shared_alloc_register_xlat_entry(const void *key_pointer, const void * void *zend_shared_alloc_get_xlat_entry(const void *key_pointer) { void *retval; - zend_ulong key = (zend_ulong)key_pointer; + zend_ulong key = (zend_ulong)(uintptr_t)key_pointer; key = zend_rotr3(key); if ((retval = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) == NULL) { diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 265b47e52dc7..da0631a9af89 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -146,8 +146,6 @@ typedef psetid_t cpu_set_t; # define NSIG 32 #endif -#define LONG_CONST(c) (zend_long) c - #include "Zend/zend_enum.h" #include "Zend/zend_max_execution_timer.h" @@ -234,8 +232,8 @@ PHP_RSHUTDOWN_FUNCTION(pcntl) /* Reset all signals to their default disposition */ ZEND_HASH_FOREACH_NUM_KEY_VAL(&PCNTL_G(php_signal_table), signo, handle) { - if (Z_TYPE_P(handle) != IS_LONG || Z_LVAL_P(handle) != (zend_long)SIG_DFL) { - php_signal(signo, (Sigfunc *)(zend_long)SIG_DFL, false); + if (Z_TYPE_P(handle) != IS_LONG || Z_LVAL_P(handle) != ZEND_PTR_TO_ZEND_LONG(SIG_DFL)) { + php_signal(signo, (Sigfunc *) (void *) SIG_DFL, false); } } ZEND_HASH_FOREACH_END(); @@ -827,11 +825,11 @@ PHP_FUNCTION(pcntl_signal) /* Special long value case for SIG_DFL and SIG_IGN */ if (Z_TYPE_P(handle) == IS_LONG) { - if (Z_LVAL_P(handle) != (zend_long) SIG_DFL && Z_LVAL_P(handle) != (zend_long) SIG_IGN) { + if (Z_LVAL_P(handle) != ZEND_PTR_TO_ZEND_LONG(SIG_DFL) && Z_LVAL_P(handle) != ZEND_PTR_TO_ZEND_LONG(SIG_IGN)) { zend_argument_value_error(2, "must be either SIG_DFL or SIG_IGN when an integer value is given"); RETURN_THROWS(); } - if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), restart_syscalls) == (void *)SIG_ERR) { + if (php_signal(signo, (Sigfunc *) ZEND_LONG_TO_PTR(Z_LVAL_P(handle)), restart_syscalls) == (void *)SIG_ERR) { PCNTL_G(last_error) = errno; php_error_docref(NULL, E_WARNING, "Error assigning signal"); RETURN_FALSE; @@ -879,7 +877,7 @@ PHP_FUNCTION(pcntl_signal_get_handler) if ((prev_handle = zend_hash_index_find(&PCNTL_G(php_signal_table), signo)) != NULL) { RETURN_COPY(prev_handle); } else { - RETURN_LONG((zend_long)SIG_DFL); + RETURN_LONG(ZEND_PTR_TO_ZEND_LONG(SIG_DFL)); } } @@ -1145,7 +1143,7 @@ static void pcntl_siginfo_to_zval(int signo, siginfo_t *siginfo, zval *user_sigi case SIGFPE: case SIGSEGV: case SIGBUS: - add_assoc_long_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo->si_addr); + add_assoc_long_ex(user_siginfo, "addr", sizeof("addr")-1, ZEND_PTR_TO_ZEND_LONG(siginfo->si_addr)); break; #if defined(SIGPOLL) && !defined(__CYGWIN__) case SIGPOLL: diff --git a/ext/pcntl/pcntl.stub.php b/ext/pcntl/pcntl.stub.php index 1ab52d025036..8b5b2432e0d3 100644 --- a/ext/pcntl/pcntl.stub.php +++ b/ext/pcntl/pcntl.stub.php @@ -12,42 +12,42 @@ #ifdef WNOHANG /** * @var int - * @cvalue LONG_CONST(WNOHANG) + * @cvalue ZEND_PTR_TO_ZEND_LONG(WNOHANG) */ const WNOHANG = UNKNOWN; #endif #ifdef WUNTRACED /** * @var int - * @cvalue LONG_CONST(WUNTRACED) + * @cvalue ZEND_PTR_TO_ZEND_LONG(WUNTRACED) */ const WUNTRACED = UNKNOWN; #endif #ifdef HAVE_WCONTINUED /** * @var int - * @cvalue LONG_CONST(WCONTINUED) + * @cvalue ZEND_PTR_TO_ZEND_LONG(WCONTINUED) */ const WCONTINUED = UNKNOWN; #endif #if defined (HAVE_DECL_WEXITED) && HAVE_DECL_WEXITED == 1 /** * @var int - * @cvalue LONG_CONST(WEXITED) + * @cvalue ZEND_PTR_TO_ZEND_LONG(WEXITED) */ const WEXITED = UNKNOWN; #endif #if defined (HAVE_DECL_WSTOPPED) && HAVE_DECL_WSTOPPED == 1 /** * @var int - * @cvalue LONG_CONST(WSTOPPED) + * @cvalue ZEND_PTR_TO_ZEND_LONG(WSTOPPED) */ const WSTOPPED = UNKNOWN; #endif #if defined (HAVE_DECL_WNOWAIT) && HAVE_DECL_WNOWAIT== 1 /** * @var int - * @cvalue LONG_CONST(WNOWAIT) + * @cvalue ZEND_PTR_TO_ZEND_LONG(WNOWAIT) */ const WNOWAIT = UNKNOWN; #endif @@ -57,17 +57,17 @@ #ifdef HAVE_POSIX_IDTYPES /** * @var int - * @cvalue LONG_CONST(P_ALL) + * @cvalue ZEND_PTR_TO_ZEND_LONG(P_ALL) */ const P_ALL = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(P_PID) + * @cvalue ZEND_PTR_TO_ZEND_LONG(P_PID) */ const P_PID = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(P_PGID) + * @cvalue ZEND_PTR_TO_ZEND_LONG(P_PGID) */ const P_PGID = UNKNOWN; #endif @@ -75,7 +75,7 @@ #ifdef HAVE_LINUX_IDTYPES /** * @var int - * @cvalue LONG_CONST(P_PIDFD) + * @cvalue ZEND_PTR_TO_ZEND_LONG(P_PIDFD) */ const P_PIDFD = UNKNOWN; #endif @@ -83,17 +83,17 @@ #ifdef HAVE_NETBSD_IDTYPES /** * @var int - * @cvalue LONG_CONST(P_UID) + * @cvalue ZEND_PTR_TO_ZEND_LONG(P_UID) */ const P_UID = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(P_GID) + * @cvalue ZEND_PTR_TO_ZEND_LONG(P_GID) */ const P_GID = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(P_SID) + * @cvalue ZEND_PTR_TO_ZEND_LONG(P_SID) */ const P_SID = UNKNOWN; #endif @@ -101,7 +101,7 @@ #ifdef HAVE_FREEBSD_IDTYPES /** * @var int - * @cvalue LONG_CONST(P_JAILID) + * @cvalue ZEND_PTR_TO_ZEND_LONG(P_JAILID) */ const P_JAILID = UNKNOWN; #endif @@ -111,244 +111,244 @@ /** * @var int - * @cvalue LONG_CONST(SIG_IGN) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIG_IGN) */ const SIG_IGN = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIG_DFL) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIG_DFL) */ const SIG_DFL = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIG_ERR) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIG_ERR) */ const SIG_ERR = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGHUP) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGHUP) */ const SIGHUP = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGINT) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGINT) */ const SIGINT = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGQUIT) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGQUIT) */ const SIGQUIT = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGILL) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGILL) */ const SIGILL = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGTRAP) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGTRAP) */ const SIGTRAP = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGABRT) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGABRT) */ const SIGABRT = UNKNOWN; #ifdef SIGIOT /** * @var int - * @cvalue LONG_CONST(SIGIOT) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGIOT) */ const SIGIOT = UNKNOWN; #endif /** * @var int - * @cvalue LONG_CONST(SIGBUS) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGBUS) */ const SIGBUS = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGFPE) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGFPE) */ const SIGFPE = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGKILL) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGKILL) */ const SIGKILL = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGUSR1) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGUSR1) */ const SIGUSR1 = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGSEGV) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGSEGV) */ const SIGSEGV = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGUSR2) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGUSR2) */ const SIGUSR2 = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGPIPE) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGPIPE) */ const SIGPIPE = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGALRM) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGALRM) */ const SIGALRM = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGTERM) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGTERM) */ const SIGTERM = UNKNOWN; #ifdef SIGSTKFLT /** * @var int - * @cvalue LONG_CONST(SIGSTKFLT) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGSTKFLT) */ const SIGSTKFLT = UNKNOWN; #endif #ifdef SIGCLD /** * @var int - * @cvalue LONG_CONST(SIGCLD) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGCLD) */ const SIGCLD = UNKNOWN; #endif #ifdef SIGCHLD /** * @var int - * @cvalue LONG_CONST(SIGCHLD) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGCHLD) */ const SIGCHLD = UNKNOWN; #endif /** * @var int - * @cvalue LONG_CONST(SIGCONT) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGCONT) */ const SIGCONT = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGSTOP) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGSTOP) */ const SIGSTOP = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGTSTP) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGTSTP) */ const SIGTSTP = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGTTIN) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGTTIN) */ const SIGTTIN = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGTTOU) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGTTOU) */ const SIGTTOU = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGURG) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGURG) */ const SIGURG = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGXCPU) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGXCPU) */ const SIGXCPU = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGXFSZ) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGXFSZ) */ const SIGXFSZ = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGVTALRM) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGVTALRM) */ const SIGVTALRM = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGPROF) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGPROF) */ const SIGPROF = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGWINCH) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGWINCH) */ const SIGWINCH = UNKNOWN; #ifdef SIGPOLL /** * @var int - * @cvalue LONG_CONST(SIGPOLL) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGPOLL) */ const SIGPOLL = UNKNOWN; #endif #ifdef SIGIO /** * @var int - * @cvalue LONG_CONST(SIGIO) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGIO) */ const SIGIO = UNKNOWN; #endif #ifdef SIGPWR /** * @var int - * @cvalue LONG_CONST(SIGPWR) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGPWR) */ const SIGPWR = UNKNOWN; #endif #ifdef SIGINFO /** * @var int - * @cvalue LONG_CONST(SIGINFO) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGINFO) */ const SIGINFO = UNKNOWN; #endif #ifdef SIGSYS /** * @var int - * @cvalue LONG_CONST(SIGSYS) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGSYS) */ const SIGSYS = UNKNOWN; /** * @var int - * @cvalue LONG_CONST(SIGSYS) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGSYS) */ const SIGBABY = UNKNOWN; #endif #ifdef SIGCKPT /** * @var int - * @cvalue LONG_CONST(SIGCKPT) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGCKPT) */ const SIGCKPT = UNKNOWN; #endif #ifdef SIGCKPTEXIT /** * @var int - * @cvalue LONG_CONST(SIGCKPTEXIT) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGCKPTEXIT) */ const SIGCKPTEXIT = UNKNOWN; #endif #ifdef SIGRTMIN /** * @var int - * @cvalue LONG_CONST(SIGRTMIN) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGRTMIN) */ const SIGRTMIN = UNKNOWN; #endif #ifdef SIGRTMAX /** * @var int - * @cvalue LONG_CONST(SIGRTMAX) + * @cvalue ZEND_PTR_TO_ZEND_LONG(SIGRTMAX) */ const SIGRTMAX = UNKNOWN; #endif diff --git a/ext/pcntl/pcntl_arginfo.h b/ext/pcntl/pcntl_arginfo.h index a9d6bb010e29..22ea951efbf0 100644 --- a/ext/pcntl/pcntl_arginfo.h +++ b/ext/pcntl/pcntl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit pcntl.stub.php instead. - * Stub hash: ec6306e93fad6d127ff880fc01736ac287619cf7 + * Stub hash: 069a83d911b2cea1f5d208cb40ff355ed5a361e2 * Has decl header: yes */ #include "zend_constants.h" @@ -303,107 +303,107 @@ static const zend_function_entry ext_functions[] = { static void register_pcntl_symbols(int module_number) { #if defined(WNOHANG) - REGISTER_LONG_CONSTANT("WNOHANG", LONG_CONST(WNOHANG), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("WNOHANG", ZEND_PTR_TO_ZEND_LONG(WNOHANG), CONST_PERSISTENT); #endif #if defined(WUNTRACED) - REGISTER_LONG_CONSTANT("WUNTRACED", LONG_CONST(WUNTRACED), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("WUNTRACED", ZEND_PTR_TO_ZEND_LONG(WUNTRACED), CONST_PERSISTENT); #endif #if defined(HAVE_WCONTINUED) - REGISTER_LONG_CONSTANT("WCONTINUED", LONG_CONST(WCONTINUED), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("WCONTINUED", ZEND_PTR_TO_ZEND_LONG(WCONTINUED), CONST_PERSISTENT); #endif #if defined (HAVE_DECL_WEXITED) && HAVE_DECL_WEXITED == 1 - REGISTER_LONG_CONSTANT("WEXITED", LONG_CONST(WEXITED), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("WEXITED", ZEND_PTR_TO_ZEND_LONG(WEXITED), CONST_PERSISTENT); #endif #if defined (HAVE_DECL_WSTOPPED) && HAVE_DECL_WSTOPPED == 1 - REGISTER_LONG_CONSTANT("WSTOPPED", LONG_CONST(WSTOPPED), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("WSTOPPED", ZEND_PTR_TO_ZEND_LONG(WSTOPPED), CONST_PERSISTENT); #endif #if defined (HAVE_DECL_WNOWAIT) && HAVE_DECL_WNOWAIT== 1 - REGISTER_LONG_CONSTANT("WNOWAIT", LONG_CONST(WNOWAIT), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("WNOWAIT", ZEND_PTR_TO_ZEND_LONG(WNOWAIT), CONST_PERSISTENT); #endif #if defined(HAVE_WAITID) && defined(HAVE_POSIX_IDTYPES) - REGISTER_LONG_CONSTANT("P_ALL", LONG_CONST(P_ALL), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("P_PID", LONG_CONST(P_PID), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("P_PGID", LONG_CONST(P_PGID), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("P_ALL", ZEND_PTR_TO_ZEND_LONG(P_ALL), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("P_PID", ZEND_PTR_TO_ZEND_LONG(P_PID), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("P_PGID", ZEND_PTR_TO_ZEND_LONG(P_PGID), CONST_PERSISTENT); #endif #if defined(HAVE_WAITID) && defined(HAVE_LINUX_IDTYPES) - REGISTER_LONG_CONSTANT("P_PIDFD", LONG_CONST(P_PIDFD), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("P_PIDFD", ZEND_PTR_TO_ZEND_LONG(P_PIDFD), CONST_PERSISTENT); #endif #if defined(HAVE_WAITID) && defined(HAVE_NETBSD_IDTYPES) - REGISTER_LONG_CONSTANT("P_UID", LONG_CONST(P_UID), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("P_GID", LONG_CONST(P_GID), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("P_SID", LONG_CONST(P_SID), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("P_UID", ZEND_PTR_TO_ZEND_LONG(P_UID), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("P_GID", ZEND_PTR_TO_ZEND_LONG(P_GID), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("P_SID", ZEND_PTR_TO_ZEND_LONG(P_SID), CONST_PERSISTENT); #endif #if defined(HAVE_WAITID) && defined(HAVE_FREEBSD_IDTYPES) - REGISTER_LONG_CONSTANT("P_JAILID", LONG_CONST(P_JAILID), CONST_PERSISTENT); -#endif - REGISTER_LONG_CONSTANT("SIG_IGN", LONG_CONST(SIG_IGN), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIG_DFL", LONG_CONST(SIG_DFL), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIG_ERR", LONG_CONST(SIG_ERR), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGHUP", LONG_CONST(SIGHUP), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGINT", LONG_CONST(SIGINT), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGQUIT", LONG_CONST(SIGQUIT), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGILL", LONG_CONST(SIGILL), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGTRAP", LONG_CONST(SIGTRAP), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGABRT", LONG_CONST(SIGABRT), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("P_JAILID", ZEND_PTR_TO_ZEND_LONG(P_JAILID), CONST_PERSISTENT); +#endif + REGISTER_LONG_CONSTANT("SIG_IGN", ZEND_PTR_TO_ZEND_LONG(SIG_IGN), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIG_DFL", ZEND_PTR_TO_ZEND_LONG(SIG_DFL), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIG_ERR", ZEND_PTR_TO_ZEND_LONG(SIG_ERR), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGHUP", ZEND_PTR_TO_ZEND_LONG(SIGHUP), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGINT", ZEND_PTR_TO_ZEND_LONG(SIGINT), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGQUIT", ZEND_PTR_TO_ZEND_LONG(SIGQUIT), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGILL", ZEND_PTR_TO_ZEND_LONG(SIGILL), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGTRAP", ZEND_PTR_TO_ZEND_LONG(SIGTRAP), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGABRT", ZEND_PTR_TO_ZEND_LONG(SIGABRT), CONST_PERSISTENT); #if defined(SIGIOT) - REGISTER_LONG_CONSTANT("SIGIOT", LONG_CONST(SIGIOT), CONST_PERSISTENT); -#endif - REGISTER_LONG_CONSTANT("SIGBUS", LONG_CONST(SIGBUS), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGFPE", LONG_CONST(SIGFPE), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGKILL", LONG_CONST(SIGKILL), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGUSR1", LONG_CONST(SIGUSR1), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGSEGV", LONG_CONST(SIGSEGV), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGUSR2", LONG_CONST(SIGUSR2), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGPIPE", LONG_CONST(SIGPIPE), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGALRM", LONG_CONST(SIGALRM), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGTERM", LONG_CONST(SIGTERM), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGIOT", ZEND_PTR_TO_ZEND_LONG(SIGIOT), CONST_PERSISTENT); +#endif + REGISTER_LONG_CONSTANT("SIGBUS", ZEND_PTR_TO_ZEND_LONG(SIGBUS), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGFPE", ZEND_PTR_TO_ZEND_LONG(SIGFPE), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGKILL", ZEND_PTR_TO_ZEND_LONG(SIGKILL), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGUSR1", ZEND_PTR_TO_ZEND_LONG(SIGUSR1), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGSEGV", ZEND_PTR_TO_ZEND_LONG(SIGSEGV), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGUSR2", ZEND_PTR_TO_ZEND_LONG(SIGUSR2), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGPIPE", ZEND_PTR_TO_ZEND_LONG(SIGPIPE), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGALRM", ZEND_PTR_TO_ZEND_LONG(SIGALRM), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGTERM", ZEND_PTR_TO_ZEND_LONG(SIGTERM), CONST_PERSISTENT); #if defined(SIGSTKFLT) - REGISTER_LONG_CONSTANT("SIGSTKFLT", LONG_CONST(SIGSTKFLT), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGSTKFLT", ZEND_PTR_TO_ZEND_LONG(SIGSTKFLT), CONST_PERSISTENT); #endif #if defined(SIGCLD) - REGISTER_LONG_CONSTANT("SIGCLD", LONG_CONST(SIGCLD), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGCLD", ZEND_PTR_TO_ZEND_LONG(SIGCLD), CONST_PERSISTENT); #endif #if defined(SIGCHLD) - REGISTER_LONG_CONSTANT("SIGCHLD", LONG_CONST(SIGCHLD), CONST_PERSISTENT); -#endif - REGISTER_LONG_CONSTANT("SIGCONT", LONG_CONST(SIGCONT), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGSTOP", LONG_CONST(SIGSTOP), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGTSTP", LONG_CONST(SIGTSTP), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGTTIN", LONG_CONST(SIGTTIN), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGTTOU", LONG_CONST(SIGTTOU), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGURG", LONG_CONST(SIGURG), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGXCPU", LONG_CONST(SIGXCPU), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGXFSZ", LONG_CONST(SIGXFSZ), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGVTALRM", LONG_CONST(SIGVTALRM), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGPROF", LONG_CONST(SIGPROF), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGWINCH", LONG_CONST(SIGWINCH), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGCHLD", ZEND_PTR_TO_ZEND_LONG(SIGCHLD), CONST_PERSISTENT); +#endif + REGISTER_LONG_CONSTANT("SIGCONT", ZEND_PTR_TO_ZEND_LONG(SIGCONT), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGSTOP", ZEND_PTR_TO_ZEND_LONG(SIGSTOP), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGTSTP", ZEND_PTR_TO_ZEND_LONG(SIGTSTP), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGTTIN", ZEND_PTR_TO_ZEND_LONG(SIGTTIN), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGTTOU", ZEND_PTR_TO_ZEND_LONG(SIGTTOU), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGURG", ZEND_PTR_TO_ZEND_LONG(SIGURG), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGXCPU", ZEND_PTR_TO_ZEND_LONG(SIGXCPU), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGXFSZ", ZEND_PTR_TO_ZEND_LONG(SIGXFSZ), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGVTALRM", ZEND_PTR_TO_ZEND_LONG(SIGVTALRM), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGPROF", ZEND_PTR_TO_ZEND_LONG(SIGPROF), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGWINCH", ZEND_PTR_TO_ZEND_LONG(SIGWINCH), CONST_PERSISTENT); #if defined(SIGPOLL) - REGISTER_LONG_CONSTANT("SIGPOLL", LONG_CONST(SIGPOLL), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGPOLL", ZEND_PTR_TO_ZEND_LONG(SIGPOLL), CONST_PERSISTENT); #endif #if defined(SIGIO) - REGISTER_LONG_CONSTANT("SIGIO", LONG_CONST(SIGIO), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGIO", ZEND_PTR_TO_ZEND_LONG(SIGIO), CONST_PERSISTENT); #endif #if defined(SIGPWR) - REGISTER_LONG_CONSTANT("SIGPWR", LONG_CONST(SIGPWR), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGPWR", ZEND_PTR_TO_ZEND_LONG(SIGPWR), CONST_PERSISTENT); #endif #if defined(SIGINFO) - REGISTER_LONG_CONSTANT("SIGINFO", LONG_CONST(SIGINFO), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGINFO", ZEND_PTR_TO_ZEND_LONG(SIGINFO), CONST_PERSISTENT); #endif #if defined(SIGSYS) - REGISTER_LONG_CONSTANT("SIGSYS", LONG_CONST(SIGSYS), CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SIGBABY", LONG_CONST(SIGSYS), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGSYS", ZEND_PTR_TO_ZEND_LONG(SIGSYS), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGBABY", ZEND_PTR_TO_ZEND_LONG(SIGSYS), CONST_PERSISTENT); #endif #if defined(SIGCKPT) - REGISTER_LONG_CONSTANT("SIGCKPT", LONG_CONST(SIGCKPT), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGCKPT", ZEND_PTR_TO_ZEND_LONG(SIGCKPT), CONST_PERSISTENT); #endif #if defined(SIGCKPTEXIT) - REGISTER_LONG_CONSTANT("SIGCKPTEXIT", LONG_CONST(SIGCKPTEXIT), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGCKPTEXIT", ZEND_PTR_TO_ZEND_LONG(SIGCKPTEXIT), CONST_PERSISTENT); #endif #if defined(SIGRTMIN) - REGISTER_LONG_CONSTANT("SIGRTMIN", LONG_CONST(SIGRTMIN), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGRTMIN", ZEND_PTR_TO_ZEND_LONG(SIGRTMIN), CONST_PERSISTENT); #endif #if defined(SIGRTMAX) - REGISTER_LONG_CONSTANT("SIGRTMAX", LONG_CONST(SIGRTMAX), CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGRTMAX", ZEND_PTR_TO_ZEND_LONG(SIGRTMAX), CONST_PERSISTENT); #endif #if (defined(HAVE_GETPRIORITY) || defined(HAVE_SETPRIORITY)) REGISTER_LONG_CONSTANT("PRIO_PGRP", PRIO_PGRP, CONST_PERSISTENT); diff --git a/ext/pcntl/pcntl_decl.h b/ext/pcntl/pcntl_decl.h index a0fdb4dde755..1e23c4e1b355 100644 --- a/ext/pcntl/pcntl_decl.h +++ b/ext/pcntl/pcntl_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit pcntl.stub.php instead. - * Stub hash: ec6306e93fad6d127ff880fc01736ac287619cf7 */ + * Stub hash: 069a83d911b2cea1f5d208cb40ff355ed5a361e2 */ -#ifndef ZEND_PCNTL_DECL_ec6306e93fad6d127ff880fc01736ac287619cf7_H -#define ZEND_PCNTL_DECL_ec6306e93fad6d127ff880fc01736ac287619cf7_H +#ifndef ZEND_PCNTL_DECL_069a83d911b2cea1f5d208cb40ff355ed5a361e2_H +#define ZEND_PCNTL_DECL_069a83d911b2cea1f5d208cb40ff355ed5a361e2_H typedef enum zend_enum_Pcntl_QosClass { ZEND_ENUM_Pcntl_QosClass_UserInteractive = 1, @@ -12,4 +12,4 @@ typedef enum zend_enum_Pcntl_QosClass { ZEND_ENUM_Pcntl_QosClass_Background = 5, } zend_enum_Pcntl_QosClass; -#endif /* ZEND_PCNTL_DECL_ec6306e93fad6d127ff880fc01736ac287619cf7_H */ +#endif /* ZEND_PCNTL_DECL_069a83d911b2cea1f5d208cb40ff355ed5a361e2_H */ diff --git a/ext/shmop/shmop.c b/ext/shmop/shmop.c index 47ca1c2112ef..c4835f771450 100644 --- a/ext/shmop/shmop.c +++ b/ext/shmop/shmop.c @@ -182,6 +182,9 @@ PHP_FUNCTION(shmop_open) if (shmop->shmflg & IPC_CREAT && shmop->size < 1) { zend_argument_value_error(4, "must be greater than 0 for the \"c\" and \"n\" access modes"); goto err; + } else if (ZEND_LONG_SIZE_T_OVFL(shmop->size)) { + zend_argument_value_error(4, "must be less than or equal to %zu", SIZE_MAX); + goto err; } shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg); @@ -196,7 +199,7 @@ PHP_FUNCTION(shmop_open) goto err; } - if (shm.shm_segsz > ZEND_LONG_MAX) { + if (ZEND_SIZE_T_ZEND_LONG_OVFL(shm.shm_segsz)) { zend_argument_value_error(4, "is too large"); goto err; } diff --git a/ext/sockets/sendrecvmsg.c b/ext/sockets/sendrecvmsg.c index cc268bd68b0a..a8f725d04647 100644 --- a/ext/sockets/sendrecvmsg.c +++ b/ext/sockets/sendrecvmsg.c @@ -314,7 +314,7 @@ PHP_FUNCTION(socket_cmsg_space) size_t size = entry->size + n * entry->var_el_size; size_t total_size = CMSG_SPACE(size); if (n > n_max /* zend_long overflow */ - || total_size > ZEND_LONG_MAX + || ZEND_SIZE_T_ZEND_LONG_OVFL(total_size) || total_size < size /* align overflow */) { zend_argument_value_error(3, "is too large"); RETURN_THROWS(); diff --git a/ext/standard/crypt_sha256.c b/ext/standard/crypt_sha256.c index 3f3d9cdeb03c..d2488b185397 100644 --- a/ext/standard/crypt_sha256.c +++ b/ext/standard/crypt_sha256.c @@ -510,7 +510,7 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b if (rounds_custom) { #ifdef PHP_WIN32 - int n = _snprintf(cp, MAX(0, buflen), "%s" ZEND_ULONG_FMT "$", sha256_rounds_prefix, rounds); + int n = _snprintf(cp, MAX(0, buflen), "%s%zu$", sha256_rounds_prefix, rounds); #else int n = snprintf(cp, MAX(0, buflen), "%s%zu$", sha256_rounds_prefix, rounds); #endif diff --git a/ext/standard/crypt_sha512.c b/ext/standard/crypt_sha512.c index 4a308e2f9af2..04f8448ff6d5 100644 --- a/ext/standard/crypt_sha512.c +++ b/ext/standard/crypt_sha512.c @@ -549,7 +549,7 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) if (rounds_custom) { #ifdef PHP_WIN32 - int n = _snprintf(cp, MAX(0, buflen), "%s" ZEND_ULONG_FMT "$", sha512_rounds_prefix, rounds); + int n = _snprintf(cp, MAX(0, buflen), "%s%zu$", sha512_rounds_prefix, rounds); #else int n = snprintf(cp, MAX(0, buflen), "%s%zu$", sha512_rounds_prefix, rounds); #endif diff --git a/ext/standard/file.c b/ext/standard/file.c index b52e5ba9525f..e734c7d98a20 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -380,7 +380,8 @@ PHP_FUNCTION(file_get_contents) bool use_include_path = 0; php_stream *stream; zend_long offset = 0; - zend_long maxlen; + zend_long maxlen_zl; + size_t maxlen; bool maxlen_is_null = 1; zval *zcontext = NULL; php_stream_context *context = NULL; @@ -393,14 +394,19 @@ PHP_FUNCTION(file_get_contents) Z_PARAM_BOOL(use_include_path) Z_PARAM_RESOURCE_OR_NULL(zcontext) Z_PARAM_LONG(offset) - Z_PARAM_LONG_OR_NULL(maxlen, maxlen_is_null) + Z_PARAM_LONG_OR_NULL(maxlen_zl, maxlen_is_null) ZEND_PARSE_PARAMETERS_END(); if (maxlen_is_null) { - maxlen = (ssize_t) PHP_STREAM_COPY_ALL; - } else if (maxlen < 0) { + maxlen = PHP_STREAM_COPY_ALL; + } else if (UNEXPECTED(maxlen_zl < 0)) { zend_argument_value_error(5, "must be greater than or equal to 0"); RETURN_THROWS(); + } else if (ZEND_LONG_SIZE_T_OVFL(maxlen_zl)) { + zend_argument_value_error(5, "must be less than or equal to %zu", SIZE_MAX); + RETURN_THROWS(); + } else { + maxlen = (size_t) maxlen_zl; } php_stream_error_operation_begin(); @@ -504,9 +510,9 @@ PHP_FUNCTION(file_put_contents) if (php_stream_copy_to_stream_ex(srcstream, stream, PHP_STREAM_COPY_ALL, &len) != SUCCESS) { numbytes = -1; } else { - if (len > ZEND_LONG_MAX) { + if (ZEND_SIZE_T_ZEND_LONG_OVFL(len)) { php_error_docref(NULL, E_WARNING, "content truncated from %zu to " ZEND_LONG_FMT " bytes", len, ZEND_LONG_MAX); - len = ZEND_LONG_MAX; + len = (size_t) ZEND_LONG_MAX; } numbytes = len; } @@ -907,13 +913,16 @@ PHPAPI PHP_FUNCTION(fgets) RETVAL_STRINGL(buf, line_len); efree(buf); } else { - if (len <= 0) { + if (UNEXPECTED(len <= 0)) { zend_argument_value_error(2, "must be greater than 0"); RETURN_THROWS(); + } else if (ZEND_LONG_ZSTR_LEN_OVFL(len)) { + zend_argument_value_error(2, "must be less than or equal to %zu", ZSTR_MAX_LEN); + RETURN_THROWS(); } - str = zend_string_alloc(len, 0); - buf = php_stream_get_line(stream, ZSTR_VAL(str), len, &line_len); + str = zend_string_alloc((size_t) len, 0); + buf = php_stream_get_line(stream, ZSTR_VAL(str), (size_t) len, &line_len); php_stream_error_operation_end_for_stream(stream); if (buf == NULL) { zend_string_efree(str); @@ -1018,7 +1027,11 @@ PHPAPI PHP_FUNCTION(fwrite) } else if (maxlen <= 0) { num_bytes = 0; } else { +#if SIZEOF_SIZE_T >= SIZEOF_ZEND_LONG num_bytes = MIN((size_t) maxlen, inputlen); +#else + num_bytes = MIN(maxlen, (zend_long) inputlen); +#endif } if (!num_bytes) { @@ -1365,9 +1378,12 @@ PHP_FUNCTION(ftruncate) Z_PARAM_LONG(size) ZEND_PARSE_PARAMETERS_END(); - if (size < 0) { + if (UNEXPECTED(size < 0)) { zend_argument_value_error(2, "must be greater than or equal to 0"); RETURN_THROWS(); + } else if (ZEND_LONG_SIZE_T_OVFL(size)) { + zend_argument_value_error(2, "must be less than or equal to %zu", SIZE_MAX); + RETURN_THROWS(); } php_stream_error_operation_begin(); @@ -1613,9 +1629,12 @@ PHPAPI PHP_FUNCTION(fread) Z_PARAM_LONG(len) ZEND_PARSE_PARAMETERS_END(); - if (len <= 0) { + if (UNEXPECTED(len <= 0)) { zend_argument_value_error(2, "must be greater than 0"); RETURN_THROWS(); + } else if (ZEND_LONG_ZSTR_LEN_OVFL(len)) { + zend_argument_value_error(2, "must be less than or equal to %zu", ZSTR_MAX_LEN); + RETURN_THROWS(); } php_stream_error_operation_begin(); @@ -1869,9 +1888,15 @@ PHP_FUNCTION(fgetcsv) if (len_is_null || len == 0) { len = -1; - } else if (len < 0 || len > (ZEND_LONG_MAX - 1)) { +#if SIZEOF_SIZE_T >= SIZEOF_ZEND_LONG + } else if (UNEXPECTED(len < 0 || len > (ZEND_LONG_MAX - 1))) { zend_argument_value_error(2, "must be between 0 and " ZEND_LONG_FMT, (ZEND_LONG_MAX - 1)); RETURN_THROWS(); +#else + } else if (UNEXPECTED(len < 0 || len > (SIZE_MAX - 1))) { + zend_argument_value_error(2, "must be between 0 and %zu", (SIZE_MAX - 1)); + RETURN_THROWS(); +#endif } php_stream_error_operation_begin(); diff --git a/ext/standard/head.c b/ext/standard/head.c index 34a22327b5e7..9e43381b89af 100644 --- a/ext/standard/head.c +++ b/ext/standard/head.c @@ -82,7 +82,7 @@ PHPAPI bool php_is_valid_samesite_value(zend_string *value) } #define ILLEGAL_COOKIE_CHARACTER "\",\", \";\", \" \", \"\\t\", \"\\r\", \"\\n\", \"\\013\", or \"\\014\"" -PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t expires, +PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, zend_long expires, zend_string *path, zend_string *domain, bool secure, bool httponly, zend_string *samesite, bool partitioned, bool url_encode) { @@ -115,7 +115,8 @@ PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t e get_active_function_name()); return FAILURE; } -#ifdef ZEND_ENABLE_ZVAL_LONG64 + +#if SIZEOF_ZEND_LONG >= 8 if (expires >= 253402300800) { zend_value_error("%s(): \"expires\" option cannot have a year greater than 9999", get_active_function_name()); @@ -156,7 +157,7 @@ PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t e } if (expires > 0) { - double diff; + zend_long diff; smart_str_appends(&buf, COOKIE_EXPIRES); dt = php_format_date("D, d M Y H:i:s \\G\\M\\T", sizeof("D, d M Y H:i:s \\G\\M\\T")-1, expires, 0); @@ -164,13 +165,15 @@ PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t e smart_str_append(&buf, dt); zend_string_free(dt); - diff = difftime(expires, php_time()); + /* Not difftime(): its arguments are time_t, which is narrower than + * zend_long where ZEND_INT64 is enabled on a 32bit platform. */ + diff = expires - (zend_long) php_time(); if (diff < 0) { diff = 0; } smart_str_appends(&buf, COOKIE_MAX_AGE); - smart_str_append_long(&buf, (zend_long) diff); + smart_str_append_long(&buf, diff); } } diff --git a/ext/standard/head.h b/ext/standard/head.h index 8b91371a46e2..95b43342032f 100644 --- a/ext/standard/head.h +++ b/ext/standard/head.h @@ -29,7 +29,7 @@ PHPAPI bool php_is_valid_samesite_value(zend_string *value); extern PHP_RINIT_FUNCTION(head); PHPAPI bool php_header(void); -PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t expires, +PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, zend_long expires, zend_string *path, zend_string *domain, bool secure, bool httponly, zend_string *samesite, bool partitioned, bool url_encode); diff --git a/ext/standard/math.c b/ext/standard/math.c index 20286870c7c9..4fda7f2785ad 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -1283,8 +1283,8 @@ PHPAPI zend_string *_php_math_number_format_long(zend_long num, zend_long dec, c 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, #if SIZEOF_ZEND_LONG == 8 - 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, - 1000000000000000, 10000000000000000, 100000000000000000, 1000000000000000000, 10000000000000000000ul + Z_UL(10000000000), Z_UL(100000000000), Z_UL(1000000000000), Z_UL(10000000000000), Z_UL(100000000000000), + Z_UL(1000000000000000), Z_UL(10000000000000000), Z_UL(100000000000000000), Z_UL(1000000000000000000), Z_UL(10000000000000000000) #elif SIZEOF_ZEND_LONG > 8 # error "Unknown SIZEOF_ZEND_LONG" #endif @@ -1314,7 +1314,7 @@ PHPAPI zend_string *_php_math_number_format_long(zend_long num, zend_long dec, c // rounding the number if (dec < 0) { // Check rounding to more negative places than possible - if (dec < -(sizeof(powers) / sizeof(powers[0]) - 1)) { + if (UNEXPECTED(dec < -(zend_long)(sizeof(powers) / sizeof(powers[0]) - 1))) { tmpnum = 0; } else { power = powers[-dec]; diff --git a/ext/standard/metaphone.c b/ext/standard/metaphone.c index 8f33057de5ac..0221343c6595 100644 --- a/ext/standard/metaphone.c +++ b/ext/standard/metaphone.c @@ -33,10 +33,20 @@ PHP_FUNCTION(metaphone) Z_PARAM_LONG(phones) ZEND_PARSE_PARAMETERS_END(); - if (phones < 0) { + if (UNEXPECTED(phones < 0)) { zend_argument_value_error(2, "must be greater than or equal to 0"); RETURN_THROWS(); } +#if SIZEOF_SIZE_T < SIZEOF_ZEND_LONG + /* metaphone() below allocates max_phonemes + 1 bytes, so the usable limit + * is one below ZSTR_MAX_LEN. Guarded inline rather than through + * ZEND_LONG_ZSTR_LEN_OVFL() because (zend_long) (ZSTR_MAX_LEN - 1) is + * negative where size_t is at least as wide as zend_long. */ + if (UNEXPECTED(phones > (zend_long) (ZSTR_MAX_LEN - 1))) { + zend_argument_value_error(2, "must be less than or equal to %zu", ZSTR_MAX_LEN - 1); + RETURN_THROWS(); + } +#endif metaphone((unsigned char *)ZSTR_VAL(str), ZSTR_LEN(str), phones, &result, 1); RETVAL_STR(result); diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index d544e8bf5f0f..269a5715be95 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -425,15 +425,18 @@ PHP_FUNCTION(stream_socket_recvfrom) ZEND_TRY_ASSIGN_REF_NULL(zremote); } - if (to_read <= 0) { + if (UNEXPECTED(to_read <= 0)) { zend_argument_value_error(2, "must be greater than 0"); RETURN_THROWS(); + } else if (ZEND_LONG_ZSTR_LEN_OVFL(to_read)) { + zend_argument_value_error(2, "must be less than or equal to %zu", ZSTR_MAX_LEN); + RETURN_THROWS(); } - read_buf = zend_string_alloc(to_read, 0); + read_buf = zend_string_alloc((size_t) to_read, 0); php_stream_error_operation_begin(); - recvd = php_stream_xport_recvfrom(stream, ZSTR_VAL(read_buf), to_read, (int)flags, NULL, NULL, + recvd = php_stream_xport_recvfrom(stream, ZSTR_VAL(read_buf), (size_t) to_read, (int)flags, NULL, NULL, zremote ? &remote_addr : NULL); php_stream_error_operation_end_for_stream(stream); @@ -455,22 +458,28 @@ PHP_FUNCTION(stream_socket_recvfrom) PHP_FUNCTION(stream_get_contents) { php_stream *stream; - zend_long maxlen, desiredpos = -1L; + zend_long maxlen_zl, desiredpos = -1L; + size_t maxlen; bool maxlen_is_null = 1; zend_string *contents; ZEND_PARSE_PARAMETERS_START(1, 3) PHP_Z_PARAM_STREAM(stream) Z_PARAM_OPTIONAL - Z_PARAM_LONG_OR_NULL(maxlen, maxlen_is_null) + Z_PARAM_LONG_OR_NULL(maxlen_zl, maxlen_is_null) Z_PARAM_LONG(desiredpos) ZEND_PARSE_PARAMETERS_END(); - if (maxlen_is_null) { - maxlen = (ssize_t) PHP_STREAM_COPY_ALL; - } else if (maxlen < 0 && maxlen != (ssize_t)PHP_STREAM_COPY_ALL) { + if (maxlen_is_null || maxlen_zl == -1) { + maxlen = PHP_STREAM_COPY_ALL; + } else if (UNEXPECTED(maxlen_zl < 0)) { zend_argument_value_error(2, "must be greater than or equal to -1"); RETURN_THROWS(); + } else if (ZEND_LONG_SIZE_T_OVFL(maxlen_zl)) { + zend_argument_value_error(2, "must be less than or equal to %zu", SIZE_MAX); + RETURN_THROWS(); + } else { + maxlen = (size_t) maxlen_zl; } php_stream_error_operation_begin(); @@ -496,7 +505,7 @@ PHP_FUNCTION(stream_get_contents) } } - if ((contents = php_stream_copy_to_mem(stream, maxlen, 0))) { + if ((contents = php_stream_copy_to_mem(stream, (size_t) maxlen, 0))) { RETVAL_STR(contents); } else { RETVAL_EMPTY_STRING(); @@ -526,6 +535,9 @@ PHP_FUNCTION(stream_copy_to_stream) if (maxlen_is_null) { maxlen = PHP_STREAM_COPY_ALL; + } else if (ZEND_LONG_SIZE_T_OVFL(maxlen)) { + zend_argument_value_error(3, "must be less than or equal to %zu", SIZE_MAX); + RETURN_THROWS(); } php_stream_error_operation_begin(); @@ -537,7 +549,7 @@ PHP_FUNCTION(stream_copy_to_stream) RETURN_FALSE; } - if (php_stream_copy_to_stream_ex(src, dest, maxlen, &len) != SUCCESS) { + if (php_stream_copy_to_stream_ex(src, dest, (size_t) maxlen, &len) != SUCCESS) { RETVAL_FALSE; } else { RETVAL_LONG(len); @@ -1420,16 +1432,20 @@ PHP_FUNCTION(stream_get_line) Z_PARAM_STRING(str, str_len) ZEND_PARSE_PARAMETERS_END(); - if (max_length < 0) { + if (UNEXPECTED(max_length < 0)) { zend_argument_value_error(2, "must be greater than or equal to 0"); RETURN_THROWS(); + } else if (ZEND_LONG_SIZE_T_OVFL(max_length)) { + zend_argument_value_error(2, "must be less than or equal to %zu", SIZE_MAX); + RETURN_THROWS(); } + if (!max_length) { max_length = PHP_SOCK_CHUNK_SIZE; } php_stream_error_operation_begin(); - if ((buf = php_stream_get_record(stream, max_length, str, str_len))) { + if ((buf = php_stream_get_record(stream, (size_t) max_length, str, str_len))) { RETVAL_STR(buf); } else { RETVAL_FALSE; @@ -1513,7 +1529,12 @@ PHP_FUNCTION(stream_set_write_buffer) Z_PARAM_LONG(arg2) ZEND_PARSE_PARAMETERS_END(); - buff = arg2; + if (ZEND_LONG_SIZE_T_OVFL(arg2)) { + zend_argument_value_error(2, "must be less than or equal to %zu", SIZE_MAX); + RETURN_THROWS(); + } + + buff = (size_t) arg2; php_stream_error_operation_begin(); /* if buff is 0 then set to non-buffered */ @@ -1574,7 +1595,12 @@ PHP_FUNCTION(stream_set_read_buffer) Z_PARAM_LONG(arg2) ZEND_PARSE_PARAMETERS_END(); - buff = arg2; + if (ZEND_LONG_SIZE_T_OVFL(arg2)) { + zend_argument_value_error(2, "must be less than or equal to %zu", SIZE_MAX); + RETURN_THROWS(); + } + + buff = (size_t) arg2; php_stream_error_operation_begin(); /* if buff is 0 then set to non-buffered */ diff --git a/ext/standard/string.c b/ext/standard/string.c index 577d4267ed2f..005496d39494 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -188,7 +188,7 @@ static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, bool is_strspn) if (start < 0) { start = 0; } - } else if ((size_t) start > remain_len) { + } else if (ZEND_LONG_GT_SIZE_T(start, remain_len)) { start = remain_len; } @@ -199,7 +199,7 @@ static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, bool is_strspn) if (len < 0) { len = 0; } - } else if ((size_t) len > remain_len) { + } else if (ZEND_LONG_GT_SIZE_T(len, remain_len)) { len = remain_len; } } else { @@ -1973,7 +1973,7 @@ static zend_always_inline void _zend_strpos(zval *return_value, zend_string *hay if (offset < 0) { offset += (zend_long)ZSTR_LEN(haystack); } - if (offset < 0 || (size_t)offset > ZSTR_LEN(haystack)) { + if (offset < 0 || ZEND_LONG_GT_SIZE_T(offset, ZSTR_LEN(haystack))) { zend_argument_value_error(3, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); } @@ -2054,7 +2054,7 @@ PHP_FUNCTION(stripos) if (offset < 0) { offset += (zend_long)ZSTR_LEN(haystack); } - if (offset < 0 || (size_t)offset > ZSTR_LEN(haystack)) { + if (offset < 0 || ZEND_LONG_GT_SIZE_T(offset, ZSTR_LEN(haystack))) { zend_argument_value_error(3, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); } @@ -2085,14 +2085,14 @@ PHP_FUNCTION(strrpos) ZEND_PARSE_PARAMETERS_END(); if (offset >= 0) { - if ((size_t)offset > ZSTR_LEN(haystack)) { + if (ZEND_LONG_GT_SIZE_T(offset, ZSTR_LEN(haystack))) { zend_argument_value_error(3, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); } p = ZSTR_VAL(haystack) + (size_t)offset; e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack); } else { - if (offset < -ZEND_LONG_MAX || (size_t)(-offset) > ZSTR_LEN(haystack)) { + if (offset < -ZEND_LONG_MAX || ZEND_LONG_GT_SIZE_T(-offset, ZSTR_LEN(haystack))) { zend_argument_value_error(3, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); } @@ -2135,7 +2135,7 @@ PHP_FUNCTION(strripos) Can also avoid tolower emallocs */ char lowered; if (offset >= 0) { - if ((size_t)offset > ZSTR_LEN(haystack)) { + if (ZEND_LONG_GT_SIZE_T(offset, ZSTR_LEN(haystack))) { zend_argument_value_error(3, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); } @@ -2143,7 +2143,7 @@ PHP_FUNCTION(strripos) e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack) - 1; } else { p = ZSTR_VAL(haystack); - if (offset < -ZEND_LONG_MAX || (size_t)(-offset) > ZSTR_LEN(haystack)) { + if (offset < -ZEND_LONG_MAX || ZEND_LONG_GT_SIZE_T(-offset, ZSTR_LEN(haystack))) { zend_argument_value_error(3, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); } @@ -2161,7 +2161,7 @@ PHP_FUNCTION(strripos) haystack_dup = zend_string_tolower(haystack); if (offset >= 0) { - if ((size_t)offset > ZSTR_LEN(haystack)) { + if (ZEND_LONG_GT_SIZE_T(offset, ZSTR_LEN(haystack))) { zend_string_release_ex(haystack_dup, 0); zend_argument_value_error(3, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); @@ -2169,7 +2169,7 @@ PHP_FUNCTION(strripos) p = ZSTR_VAL(haystack_dup) + offset; e = ZSTR_VAL(haystack_dup) + ZSTR_LEN(haystack); } else { - if (offset < -ZEND_LONG_MAX || (size_t)(-offset) > ZSTR_LEN(haystack)) { + if (offset < -ZEND_LONG_MAX || ZEND_LONG_GT_SIZE_T(-offset, ZSTR_LEN(haystack))) { zend_string_release_ex(haystack_dup, 0); zend_argument_value_error(3, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); @@ -2274,9 +2274,11 @@ PHP_FUNCTION(chunk_split) Z_PARAM_STRING(end, endlen) ZEND_PARSE_PARAMETERS_END(); - if (chunklen <= 0) { + if (UNEXPECTED(chunklen <= 0)) { zend_argument_value_error(2, "must be greater than 0"); RETURN_THROWS(); + } else if (ZEND_LONG_SIZE_T_OVFL(chunklen)) { + chunklen = (zend_long) SIZE_MAX; } if ((size_t)chunklen > ZSTR_LEN(str)) { @@ -2304,12 +2306,11 @@ static inline void _zend_substr(zval *return_value, zend_string *str, zend_long /* if "from" position is negative, count start position from the end * of the string */ - if (-(size_t)f > ZSTR_LEN(str)) { + f = (zend_long)ZSTR_LEN(str) + f; + if (f < 0) { f = 0; - } else { - f = (zend_long)ZSTR_LEN(str) + f; } - } else if ((size_t)f > ZSTR_LEN(str)) { + } else if (ZEND_LONG_GT_SIZE_T(f, ZSTR_LEN(str))) { RETURN_EMPTY_STRING(); } @@ -2318,13 +2319,18 @@ static inline void _zend_substr(zval *return_value, zend_string *str, zend_long /* if "length" position is negative, set it to the length * needed to stop that many chars from the end of the string */ - if (-(size_t)l > ZSTR_LEN(str) - (size_t)f) { + l = (zend_long)ZSTR_LEN(str) - f + l; + if (l < 0) { l = 0; - } else { - l = (zend_long)ZSTR_LEN(str) - f + l; } - } else if ((size_t)l > ZSTR_LEN(str) - (size_t)f) { - l = (zend_long)ZSTR_LEN(str) - f; + } else { + if (ZEND_LONG_SIZE_T_OVFL(l)) { + l = SIZE_MAX; + } + + if ((size_t)l > ZSTR_LEN(str) - (size_t)f) { + l = (zend_long)ZSTR_LEN(str) - f; + } } } else { l = (zend_long)ZSTR_LEN(str) - f; @@ -2439,7 +2445,7 @@ PHP_FUNCTION(substr_replace) if (f < 0) { f = 0; } - } else if ((size_t)f > ZSTR_LEN(str)) { + } else if (ZEND_LONG_GT_SIZE_T(f, ZSTR_LEN(str))) { f = ZSTR_LEN(str); } /* if "length" position is negative, set it to the length @@ -2452,7 +2458,7 @@ PHP_FUNCTION(substr_replace) } } - if ((size_t)l > ZSTR_LEN(str)) { + if (ZEND_LONG_GT_SIZE_T(l, ZSTR_LEN(str))) { l = ZSTR_LEN(str); } @@ -2545,7 +2551,7 @@ PHP_FUNCTION(substr_replace) if (f < 0) { f = 0; } - } else if (f > (zend_long)ZSTR_LEN(orig_str)) { + } else if (ZEND_LONG_GT_SIZE_T(f, ZSTR_LEN(orig_str))) { f = ZSTR_LEN(orig_str); } from_idx++; @@ -2559,7 +2565,7 @@ PHP_FUNCTION(substr_replace) if (f < 0) { f = 0; } - } else if (f > (zend_long)ZSTR_LEN(orig_str)) { + } else if (ZEND_LONG_GT_SIZE_T(f, ZSTR_LEN(orig_str))) { f = ZSTR_LEN(orig_str); } } @@ -2603,7 +2609,7 @@ PHP_FUNCTION(substr_replace) ZEND_ASSERT(0 <= f && f <= ZEND_LONG_MAX); ZEND_ASSERT(0 <= l && l <= ZEND_LONG_MAX); - if (((size_t) f + l) > ZSTR_LEN(orig_str)) { + if (ZEND_ULONG_GT_SIZE_T((zend_ulong) f + (zend_ulong) l, ZSTR_LEN(orig_str))) { l = ZSTR_LEN(orig_str) - f; } @@ -5627,6 +5633,9 @@ PHP_FUNCTION(str_repeat) if (mult < 0) { zend_argument_value_error(2, "must be greater than or equal to 0"); RETURN_THROWS(); + } else if (ZEND_LONG_SIZE_T_OVFL(mult)) { + zend_argument_value_error(2, "must be less than or equal to %zu", SIZE_MAX); + RETURN_THROWS(); } /* Don't waste our time if it's empty */ @@ -5635,13 +5644,13 @@ PHP_FUNCTION(str_repeat) RETURN_EMPTY_STRING(); /* Initialize the result string */ - result = zend_string_safe_alloc(ZSTR_LEN(input_str), mult, 0, 0); - result_len = ZSTR_LEN(input_str) * mult; + result = zend_string_safe_alloc(ZSTR_LEN(input_str), (size_t) mult, 0, 0); + result_len = ZSTR_LEN(input_str) * (size_t) mult; ZSTR_COPY_CONCAT_PROPERTIES(result, input_str); /* Heavy optimization for situations where input string is 1 byte long */ if (ZSTR_LEN(input_str) == 1) { - memset(ZSTR_VAL(result), *ZSTR_VAL(input_str), mult); + memset(ZSTR_VAL(result), *ZSTR_VAL(input_str), (size_t) mult); } else { const char *s, *ee; char *e; @@ -5847,7 +5856,7 @@ PHP_FUNCTION(substr_count) if (offset < 0) { offset += (zend_long)haystack_len; } - if ((offset < 0) || ((size_t)offset > haystack_len)) { + if ((offset < 0) || ZEND_LONG_GT_SIZE_T(offset, haystack_len)) { zend_argument_value_error(3, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); } @@ -5859,7 +5868,7 @@ PHP_FUNCTION(substr_count) if (length < 0) { length += haystack_len; } - if (length < 0 || ((size_t)length > haystack_len)) { + if (length < 0 || ZEND_LONG_GT_SIZE_T(length, haystack_len)) { zend_argument_value_error(4, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); } @@ -5928,6 +5937,11 @@ PHP_FUNCTION(str_pad) Z_PARAM_LONG(pad_type_val) ZEND_PARSE_PARAMETERS_END(); + if (ZEND_LONG_ZSTR_LEN_OVFL(pad_length)) { + zend_argument_value_error(2, "must be less than or equal to %zu", ZSTR_MAX_LEN); + RETURN_THROWS(); + } + /* If resulting string turns out to be shorter than input string, we simply copy the input and return. */ if (pad_length < 0 || (size_t)pad_length <= ZSTR_LEN(input)) { @@ -6277,7 +6291,7 @@ PHP_FUNCTION(str_split) RETURN_THROWS(); } - if ((size_t)split_length >= ZSTR_LEN(str)) { + if (ZEND_LONG_GTE_SIZE_T(split_length, ZSTR_LEN(str))) { if (0 == ZSTR_LEN(str)) { RETURN_EMPTY_ARRAY(); } @@ -6368,21 +6382,30 @@ PHP_FUNCTION(substr_compare) } if (offset < 0) { - offset = ZSTR_LEN(s1) + offset; - offset = (offset < 0) ? 0 : offset; + if (offset < -((zend_long) ZSTR_LEN(s1))) { + offset = 0; + } else { + offset = ZSTR_LEN(s1) + offset; + } } - if ((size_t)offset > ZSTR_LEN(s1)) { + if (ZEND_LONG_GT_SIZE_T(offset, ZSTR_LEN(s1))) { zend_argument_value_error(3, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); } - cmp_len = len ? (size_t)len : MAX(ZSTR_LEN(s2), (ZSTR_LEN(s1) - offset)); + if (!len) { + cmp_len = MAX(ZSTR_LEN(s2), (ZSTR_LEN(s1) - (size_t) offset)); + } else if (ZEND_LONG_SIZE_T_OVFL(len)) { + cmp_len = SIZE_MAX; + } else { + cmp_len = (size_t) len; + } if (!cs) { - RETURN_LONG(zend_binary_strncmp(ZSTR_VAL(s1) + offset, (ZSTR_LEN(s1) - offset), ZSTR_VAL(s2), ZSTR_LEN(s2), cmp_len)); + RETURN_LONG(zend_binary_strncmp(ZSTR_VAL(s1) + (size_t) offset, ZSTR_LEN(s1) - (size_t) offset, ZSTR_VAL(s2), ZSTR_LEN(s2), cmp_len)); } else { - RETURN_LONG(zend_binary_strncasecmp_l(ZSTR_VAL(s1) + offset, (ZSTR_LEN(s1) - offset), ZSTR_VAL(s2), ZSTR_LEN(s2), cmp_len)); + RETURN_LONG(zend_binary_strncasecmp_l(ZSTR_VAL(s1) + (size_t) offset, ZSTR_LEN(s1) - (size_t) offset, ZSTR_VAL(s2), ZSTR_LEN(s2), cmp_len)); } } /* }}} */ diff --git a/ext/standard/tests/file/fgetcsv_length_sizet.phpt b/ext/standard/tests/file/fgetcsv_length_sizet.phpt new file mode 100644 index 000000000000..3ee97763f0e9 --- /dev/null +++ b/ext/standard/tests/file/fgetcsv_length_sizet.phpt @@ -0,0 +1,21 @@ +--TEST-- +fgetcsv() $length overflow on narrow size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; +} +fclose($f); +?> +--EXPECTF-- +fgetcsv(): Argument #2 ($length) must be between 0 and %d diff --git a/ext/standard/tests/file/fgets_length_sizet.phpt b/ext/standard/tests/file/fgets_length_sizet.phpt new file mode 100644 index 000000000000..de024352e262 --- /dev/null +++ b/ext/standard/tests/file/fgets_length_sizet.phpt @@ -0,0 +1,61 @@ +--TEST-- +fgets() $length overflow on narrow size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; +} + +/* fgets() allocates its line buffer with zend_string_alloc($length), which + * adds the header and the terminating NUL to the length without an overflow + * check, so anything above PHP_STRING_MAX_LENGTH wraps to a tiny allocation + * that php_stream_get_line() then overruns. The whole window from the limit + * up to SIZE_MAX has to be refused, not just the values that exceed SIZE_MAX + * itself. */ +$sizeMax = 2 ** (PHP_SYS_SIZE * 8) - 1; + +$lengths = [ + 'STR_MAX+1' => PHP_STRING_MAX_LENGTH + 1, + 'STR_MAX+2' => PHP_STRING_MAX_LENGTH + 2, + 'STR_MAX+3' => PHP_STRING_MAX_LENGTH + 3, + 'SIZE_MAX-2' => $sizeMax - 2, + 'SIZE_MAX-1' => $sizeMax - 1, + 'SIZE_MAX' => $sizeMax, +]; + +foreach ($lengths as $label => $length) { + try { + fgets($f, $length); + echo "$label: unexpected success\n"; + } catch (ValueError $e) { + echo "$label: {$e->getMessage()}\n"; + } +} + +fclose($f); +?> +--CLEAN-- + +--EXPECTF-- +fgets(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+1: fgets(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+2: fgets(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+3: fgets(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX-2: fgets(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX-1: fgets(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX: fgets(): Argument #2 ($length) must be less than or equal to %d diff --git a/ext/standard/tests/file/file_get_contents_length_sizet.phpt b/ext/standard/tests/file/file_get_contents_length_sizet.phpt new file mode 100644 index 000000000000..064135883fe4 --- /dev/null +++ b/ext/standard/tests/file/file_get_contents_length_sizet.phpt @@ -0,0 +1,19 @@ +--TEST-- +file_get_contents() $length overflow on narrow size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +file_get_contents(): Argument #5 ($length) must be less than or equal to %d diff --git a/ext/standard/tests/file/fread_length_sizet.phpt b/ext/standard/tests/file/fread_length_sizet.phpt new file mode 100644 index 000000000000..3289c4ff5029 --- /dev/null +++ b/ext/standard/tests/file/fread_length_sizet.phpt @@ -0,0 +1,61 @@ +--TEST-- +fread() $length overflow on narrow size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; +} + +/* fread() reaches zend_string_alloc($length) via php_stream_read_to_str(). + * zend_string_alloc() adds the header and the terminating NUL to the length + * without an overflow check, so anything above PHP_STRING_MAX_LENGTH wraps to + * a tiny allocation that the following read then overruns. The whole window + * from the limit up to SIZE_MAX has to be refused, not just the values that + * exceed SIZE_MAX itself. */ +$sizeMax = 2 ** (PHP_SYS_SIZE * 8) - 1; + +$lengths = [ + 'STR_MAX+1' => PHP_STRING_MAX_LENGTH + 1, + 'STR_MAX+2' => PHP_STRING_MAX_LENGTH + 2, + 'STR_MAX+3' => PHP_STRING_MAX_LENGTH + 3, + 'SIZE_MAX-2' => $sizeMax - 2, + 'SIZE_MAX-1' => $sizeMax - 1, + 'SIZE_MAX' => $sizeMax, +]; + +foreach ($lengths as $label => $length) { + try { + fread($f, $length); + echo "$label: unexpected success\n"; + } catch (ValueError $e) { + echo "$label: {$e->getMessage()}\n"; + } +} + +fclose($f); +?> +--CLEAN-- + +--EXPECTF-- +fread(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+1: fread(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+2: fread(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+3: fread(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX-2: fread(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX-1: fread(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX: fread(): Argument #2 ($length) must be less than or equal to %d diff --git a/ext/standard/tests/file/ftruncate_error_sizet.phpt b/ext/standard/tests/file/ftruncate_error_sizet.phpt new file mode 100644 index 000000000000..2cc252182f47 --- /dev/null +++ b/ext/standard/tests/file/ftruncate_error_sizet.phpt @@ -0,0 +1,51 @@ +--TEST-- +ftruncate() on memory streams rejects sizes that exceed ZSTR_MAX_LEN +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; + } + + try { + $f = fopen('php://memory', 'w+'); + var_dump(ftruncate($f, $size)); + } catch (ValueError $e) { + echo $e->getMessage(), "\n"; + } +} + +echo "done\n"; +?> +--EXPECTF-- +bool(false) +bool(false) +bool(false) +bool(false) +ftruncate(): Argument #2 ($size) must be less than or equal to %d +ftruncate(): Argument #2 ($size) must be less than or equal to %d +ftruncate(): Argument #2 ($size) must be less than or equal to %d +ftruncate(): Argument #2 ($size) must be less than or equal to %d +bool(false) +bool(false) + +Fatal error: Allowed memory size of %d bytes exhausted at %s (tried to allocate %d bytes) in %s on line %d diff --git a/ext/standard/tests/file/fwrite.phpt b/ext/standard/tests/file/fwrite.phpt index e29c6a3507de..7f284d8c21b6 100644 --- a/ext/standard/tests/file/fwrite.phpt +++ b/ext/standard/tests/file/fwrite.phpt @@ -14,7 +14,7 @@ var_dump(fwrite($fp, "data")); $fp = fopen($filename, "w"); var_dump(fwrite($fp, "data", -1)); -var_dump(fwrite($fp, "data", 100000)); +var_dump(fwrite($fp, "data", PHP_INT_MAX)); fclose($fp); var_dump(file_get_contents($filename)); diff --git a/ext/standard/tests/file/umask_variation1.phpt b/ext/standard/tests/file/umask_variation1.phpt index f5a5a26e5577..dbab7dd52fb7 100644 --- a/ext/standard/tests/file/umask_variation1.phpt +++ b/ext/standard/tests/file/umask_variation1.phpt @@ -8,7 +8,7 @@ if (substr(PHP_OS, 0, 3) == 'WIN') { ?> --FILE-- --FILE-- +--INI-- +date.timezone=UTC +--FILE-- + 0 ? 'ok' : "WRONG: $max_age", "\n"; + echo 'Max-Age correct: ', + abs($max_age - $expected) <= 2 ? 'ok' : "WRONG: $max_age, expected about $expected", "\n"; +} +?> +--EXPECT-- +expires attribute: ok +Max-Age positive: ok +Max-Age correct: ok diff --git a/ext/standard/tests/streams/bug61115-1.phpt b/ext/standard/tests/streams/bug61115-1.phpt index 892b0f80e579..d07b7a7f0756 100644 --- a/ext/standard/tests/streams/bug61115-1.phpt +++ b/ext/standard/tests/streams/bug61115-1.phpt @@ -11,7 +11,7 @@ if (getenv("USE_ZEND_ALLOC") === "0") { $fileResourceTemp = fopen('php://temp', 'wr'); stream_context_get_options($fileResourceTemp); -ftruncate($fileResourceTemp, PHP_INT_MAX); +ftruncate($fileResourceTemp, ((2 ** (PHP_SYS_SIZE * 8-2) - 1) << 1) + 1); ?> --EXPECTF-- Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/ext/standard/tests/streams/stream_copy_to_stream_maxlength_sizet.phpt b/ext/standard/tests/streams/stream_copy_to_stream_maxlength_sizet.phpt new file mode 100644 index 000000000000..05ad051453cf --- /dev/null +++ b/ext/standard/tests/streams/stream_copy_to_stream_maxlength_sizet.phpt @@ -0,0 +1,25 @@ +--TEST-- +stream_copy_to_stream() $maxLength overflow on narrow size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; +} +fclose($src); +fclose($dst); +?> +--EXPECTF-- +stream_copy_to_stream(): Argument #3 ($length) must be less than or equal to %d diff --git a/ext/standard/tests/streams/stream_get_contents_maxlength_sizet.phpt b/ext/standard/tests/streams/stream_get_contents_maxlength_sizet.phpt new file mode 100644 index 000000000000..2f5f0930a01e --- /dev/null +++ b/ext/standard/tests/streams/stream_get_contents_maxlength_sizet.phpt @@ -0,0 +1,23 @@ +--TEST-- +stream_get_contents() $maxLength overflow on narrow size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; +} +fclose($s); +?> +--EXPECTF-- +stream_get_contents(): Argument #2 ($length) must be less than or equal to %d diff --git a/ext/standard/tests/streams/stream_get_line_length_sizet.phpt b/ext/standard/tests/streams/stream_get_line_length_sizet.phpt new file mode 100644 index 000000000000..5547ec6289aa --- /dev/null +++ b/ext/standard/tests/streams/stream_get_line_length_sizet.phpt @@ -0,0 +1,23 @@ +--TEST-- +stream_get_line() $length overflow on narrow size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; +} +fclose($s); +?> +--EXPECTF-- +stream_get_line(): Argument #2 ($length) must be less than or equal to %d diff --git a/ext/standard/tests/streams/stream_set_read_buffer_sizet.phpt b/ext/standard/tests/streams/stream_set_read_buffer_sizet.phpt new file mode 100644 index 000000000000..ae18e9179cd4 --- /dev/null +++ b/ext/standard/tests/streams/stream_set_read_buffer_sizet.phpt @@ -0,0 +1,21 @@ +--TEST-- +stream_set_read_buffer() $size overflow on narrow size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; +} +fclose($s); +?> +--EXPECTF-- +stream_set_read_buffer(): Argument #2 ($size) must be less than or equal to %d diff --git a/ext/standard/tests/streams/stream_set_write_buffer_sizet.phpt b/ext/standard/tests/streams/stream_set_write_buffer_sizet.phpt new file mode 100644 index 000000000000..a5556f57778b --- /dev/null +++ b/ext/standard/tests/streams/stream_set_write_buffer_sizet.phpt @@ -0,0 +1,21 @@ +--TEST-- +stream_set_write_buffer() $size overflow on narrow size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; +} +fclose($s); +?> +--EXPECTF-- +stream_set_write_buffer(): Argument #2 ($size) must be less than or equal to %d diff --git a/ext/standard/tests/streams/stream_socket_recvfrom_length_sizet.phpt b/ext/standard/tests/streams/stream_socket_recvfrom_length_sizet.phpt new file mode 100644 index 000000000000..8fa520d9f1d9 --- /dev/null +++ b/ext/standard/tests/streams/stream_socket_recvfrom_length_sizet.phpt @@ -0,0 +1,55 @@ +--TEST-- +stream_socket_recvfrom() $length overflow on narrow size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; +} + +/* The receive buffer comes from zend_string_alloc($length), which adds the + * header and the terminating NUL to the length without an overflow check, so + * anything above PHP_STRING_MAX_LENGTH wraps to a tiny allocation that is then + * handed to the transport as if it were $length bytes wide. The whole window + * from the limit up to SIZE_MAX has to be refused, not just the values that + * exceed SIZE_MAX itself. */ +$sizeMax = 2 ** (PHP_SYS_SIZE * 8) - 1; + +$lengths = [ + 'STR_MAX+1' => PHP_STRING_MAX_LENGTH + 1, + 'STR_MAX+2' => PHP_STRING_MAX_LENGTH + 2, + 'STR_MAX+3' => PHP_STRING_MAX_LENGTH + 3, + 'SIZE_MAX-2' => $sizeMax - 2, + 'SIZE_MAX-1' => $sizeMax - 1, + 'SIZE_MAX' => $sizeMax, +]; + +foreach ($lengths as $label => $length) { + try { + stream_socket_recvfrom($sock, $length); + echo "$label: unexpected success\n"; + } catch (ValueError $e) { + echo "$label: {$e->getMessage()}\n"; + } +} + +fclose($sock); +?> +--EXPECTF-- +stream_socket_recvfrom(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+1: stream_socket_recvfrom(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+2: stream_socket_recvfrom(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+3: stream_socket_recvfrom(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX-2: stream_socket_recvfrom(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX-1: stream_socket_recvfrom(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX: stream_socket_recvfrom(): Argument #2 ($length) must be less than or equal to %d diff --git a/ext/standard/tests/strings/bug72146.phpt b/ext/standard/tests/strings/bug72146.phpt index 72b332570ff2..3802bc2122b9 100644 --- a/ext/standard/tests/strings/bug72146.phpt +++ b/ext/standard/tests/strings/bug72146.phpt @@ -1,8 +1,8 @@ --TEST-- Bug #72146 (Integer overflow on substr_replace) --FILE-- - --EXPECT-- array(1) { diff --git a/ext/standard/tests/strings/chunk_split_variation8.phpt b/ext/standard/tests/strings/chunk_split_variation8.phpt index b0c889494e40..9d07a6a843c6 100644 --- a/ext/standard/tests/strings/chunk_split_variation8.phpt +++ b/ext/standard/tests/strings/chunk_split_variation8.phpt @@ -33,7 +33,7 @@ $values = array ( PHP_INT_MAX, // max positive integer number PHP_INT_MAX * 3, // integer overflow -PHP_INT_MAX - 1, // min negative integer - + (2 ** (PHP_SYS_SIZE * 8 - 2) - 1 << 1) + 1, // SSIZE_MAX ); @@ -80,3 +80,8 @@ chunk_split():::" chunk_split(): Argument #2 ($length) must be of type int, float given -- Iteration 8 -- chunk_split(): Argument #2 ($length) must be greater than 0 +-- Iteration 9 -- +string(129) "This's heredoc string with and + white space char. +It has _speci@l ch@r$ 2222 !!!Now \k as escape char to test +chunk_split():::" diff --git a/ext/standard/tests/strings/gh15613.phpt b/ext/standard/tests/strings/gh15613.phpt index 44c41acfddd1..20ff1620ee81 100644 --- a/ext/standard/tests/strings/gh15613.phpt +++ b/ext/standard/tests/strings/gh15613.phpt @@ -3,7 +3,7 @@ GH-15613 overflow on hex strings repeater value --SKIPIF-- --INI-- memory_limit=-1 diff --git a/ext/standard/tests/strings/metaphone_max_phonemes_sizet.phpt b/ext/standard/tests/strings/metaphone_max_phonemes_sizet.phpt new file mode 100644 index 000000000000..846bd7b3cfa5 --- /dev/null +++ b/ext/standard/tests/strings/metaphone_max_phonemes_sizet.phpt @@ -0,0 +1,57 @@ +--TEST-- +metaphone() $maxPhonemes overflow on narrow size_t +--SKIPIF-- += PHP_INT_SIZE) { + die("skip size_t is not narrower than zend_long on this platform"); +} +?> +--FILE-- +getMessage(), "\n"; +} + +error_reporting(E_ALL & ~E_DEPRECATED); + +/* metaphone() allocates $max_phonemes + 1 bytes with zend_string_alloc(), + * which adds the header and the terminating NUL to that without an overflow + * check. Its own limit is therefore one below PHP_STRING_MAX_LENGTH, so the + * window of refused values starts at the constant itself rather than above + * it. Beyond the limit the allocation wraps to a tiny buffer whose ZSTR_LEN + * is huge and the phoneme loop writes past the end of it; a long word is used + * so that an unfixed build overruns far enough to fault instead of corrupting + * the heap silently. */ +$sizeMax = 2 ** (PHP_SYS_SIZE * 8) - 1; +$word = str_repeat('Thompson', 1000); + +$lengths = [ + 'STR_MAX' => PHP_STRING_MAX_LENGTH, + 'STR_MAX+1' => PHP_STRING_MAX_LENGTH + 1, + 'STR_MAX+2' => PHP_STRING_MAX_LENGTH + 2, + 'SIZE_MAX-2' => $sizeMax - 2, + 'SIZE_MAX-1' => $sizeMax - 1, + 'SIZE_MAX' => $sizeMax, +]; + +foreach ($lengths as $label => $length) { + try { + metaphone($word, $length); + echo "$label: unexpected success\n"; + } catch (ValueError $e) { + echo "$label: {$e->getMessage()}\n"; + } +} +?> +--EXPECTF-- +Deprecated: Function metaphone() is deprecated since 8.6, use a userland phonetic matching library instead in %s on line %d +metaphone(): Argument #2 ($max_phonemes) must be less than or equal to %d +STR_MAX: metaphone(): Argument #2 ($max_phonemes) must be less than or equal to %d +STR_MAX+1: metaphone(): Argument #2 ($max_phonemes) must be less than or equal to %d +STR_MAX+2: metaphone(): Argument #2 ($max_phonemes) must be less than or equal to %d +SIZE_MAX-2: metaphone(): Argument #2 ($max_phonemes) must be less than or equal to %d +SIZE_MAX-1: metaphone(): Argument #2 ($max_phonemes) must be less than or equal to %d +SIZE_MAX: metaphone(): Argument #2 ($max_phonemes) must be less than or equal to %d diff --git a/ext/standard/tests/strings/sprintf_rope_optimization_004.phpt b/ext/standard/tests/strings/sprintf_rope_optimization_004.phpt index 27837e518a71..1e46a6570f77 100644 --- a/ext/standard/tests/strings/sprintf_rope_optimization_004.phpt +++ b/ext/standard/tests/strings/sprintf_rope_optimization_004.phpt @@ -7,22 +7,24 @@ gmp $a = new GMP("42"); $b = new GMP("-1337"); -$c = new GMP("999999999999999999999999999999999"); +$c = new GMP((string)PHP_INT_MAX); +$d = new GMP((string)PHP_INT_MIN); +$e = new GMP("999999999999999999999999999999999"); try { if (PHP_INT_SIZE == 8) { - var_dump(sprintf("%d/%d/%d/%s", $a, $b, $c, $c + 1)); - var_dump("42/-1337/2147483647/1000000000000000000000000000000000"); + var_dump(sprintf("%d/%d/%d/%d/%d/%s", $a, $b, $c, $d, $e, $e + 1)); + var_dump("42/-1337/2147483647/-2147483648/2147483647/1000000000000000000000000000000000"); } else { - var_dump("42/-1337/4089650035136921599/1000000000000000000000000000000000"); - var_dump(sprintf("%d/%d/%d/%s", $a, $b, $c, $c + 1)); + var_dump("42/-1337/9223372036854775807/-9223372036854775808/4089650035136921599/1000000000000000000000000000000000"); + var_dump(sprintf("%d/%d/%d/%d/%d/%s", $a, $b, $c, $d, $e, $e + 1)); } } catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL; echo "Done"; ?> --EXPECTF-- -string(63) "42/-1337/4089650035136921599/1000000000000000000000000000000000" -string(54) "42/-1337/2147483647/1000000000000000000000000000000000" +string(104) "42/-1337/9223372036854775807/-9223372036854775808/4089650035136921599/1000000000000000000000000000000000" +string(77) "42/-1337/2147483647/-2147483648/2147483647/1000000000000000000000000000000000" Done diff --git a/ext/standard/tests/strings/str_pad_variation1.phpt b/ext/standard/tests/strings/str_pad_variation1.phpt index cb71e61156fc..11471e58a46a 100644 --- a/ext/standard/tests/strings/str_pad_variation1.phpt +++ b/ext/standard/tests/strings/str_pad_variation1.phpt @@ -1,5 +1,7 @@ --TEST-- Test str_pad() function : usage variations - large values for '$pad_length' argument +--INI-- +memory_limit=1g --SKIPIF-- getMessage() . "\n"; } -$php_int_max_pad_length = PHP_INT_MAX; -var_dump( str_pad($input, $php_int_max_pad_length) ); - +// INT32_MAX +var_dump( str_pad($input, 2147483647) ); ?> --EXPECTF-- -*** Testing str_pad() function: with large value for for 'pad_length' argument *** +*** Testing str_pad() function: with large value for 'pad_length' argument *** str_pad(): Argument #2 ($length) must be of type int, float given Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/ext/standard/tests/strings/str_pad_variation2.phpt b/ext/standard/tests/strings/str_pad_variation2.phpt index 0bf8ad3ad80a..6377113a0e64 100644 --- a/ext/standard/tests/strings/str_pad_variation2.phpt +++ b/ext/standard/tests/strings/str_pad_variation2.phpt @@ -10,7 +10,7 @@ $string = chr(0).chr(255).chr(128).chr(234).chr(143); /* different pad_lengths */ $pad_lengths = [ - -PHP_INT_MAX, // huge negative value + (-2 ** (PHP_SYS_SIZE * 8 - 2)) << 1, // huge negative value -1, // negative value 0, // pad_length < sizeof(input_string) 9, // pad_length <= sizeof(input_string) diff --git a/ext/standard/tests/strings/str_pad_variation5.phpt b/ext/standard/tests/strings/str_pad_variation5.phpt index 1a65366c823c..fea795c8714f 100644 --- a/ext/standard/tests/strings/str_pad_variation5.phpt +++ b/ext/standard/tests/strings/str_pad_variation5.phpt @@ -4,26 +4,62 @@ Test str_pad() function : usage variations - unexpected large value for '$pad_le memory_limit=128M --SKIPIF-- = PHP_INT_SIZE) { + die("skip this test is for PHP_SYS_SIZE < PHP_INT_SIZE only"); +} if (getenv("USE_ZEND_ALLOC") === "0") { die("skip Zend MM disabled"); } ?> --FILE-- getMessage()}\n"; +} -//defining '$input' argument -$input = "Test string"; -$pad_length = PHP_INT_MAX - 16; /* zend_string header is 16 bytes */ -var_dump( str_pad($input, $pad_length) ); +/* str_pad() passes the padding count to zend_string_safe_alloc() as its + * unchecked third operand, which adds the header and the terminating NUL to + * it. Any resulting length above PHP_STRING_MAX_LENGTH wraps to a tiny + * allocation whose ZSTR_LEN is huge, and the padding is then memset() past + * the end of it. The whole window from the limit up to SIZE_MAX has to be + * refused, not just the values that exceed SIZE_MAX itself. */ +$sizeMax = 2 ** (PHP_SYS_SIZE * 8) - 1; + +$lengths = [ + 'STR_MAX+1' => PHP_STRING_MAX_LENGTH + 1, + 'STR_MAX+2' => PHP_STRING_MAX_LENGTH + 2, + 'STR_MAX+3' => PHP_STRING_MAX_LENGTH + 3, + 'SIZE_MAX-2' => $sizeMax - 2, + 'SIZE_MAX-1' => $sizeMax - 1, + 'SIZE_MAX' => $sizeMax, +]; + +foreach ($lengths as $label => $length) { + try { + var_dump( str_pad($input, $length, '-') ); + } catch (ValueError $e) { + echo "$label: {$e->getMessage()}\n"; + } +} +/* Below the limit the request is valid: it reaches the allocator and fails + * there rather than being refused or narrowed. (PHP_STRING_MAX_LENGTH itself + * is deliberately not used here: right at the top of the range the allocator + * reports the wrap of its own alignment rounding instead of the memory limit, + * and which of the two you get depends on the build.) */ +var_dump( str_pad($input, (2 ** (PHP_SYS_SIZE * 8-2) - 1 << 1) + 1) ); ?> --EXPECTF-- -*** Testing str_pad() function: with large value for for 'pad_length' argument *** +ValueError: str_pad(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+1: str_pad(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+2: str_pad(): Argument #2 ($length) must be less than or equal to %d +STR_MAX+3: str_pad(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX-2: str_pad(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX-1: str_pad(): Argument #2 ($length) must be less than or equal to %d +SIZE_MAX: str_pad(): Argument #2 ($length) must be less than or equal to %d Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/ext/standard/tests/strings/str_repeat_sizet.phpt b/ext/standard/tests/strings/str_repeat_sizet.phpt new file mode 100644 index 000000000000..e3d42a917675 --- /dev/null +++ b/ext/standard/tests/strings/str_repeat_sizet.phpt @@ -0,0 +1,47 @@ +--TEST-- +str_repeat(): $times must fit into size_t when zend_long is wider +--SKIPIF-- += PHP_INT_SIZE) { + die("skip this test is for PHP_SYS_SIZE < PHP_INT_SIZE only"); +} +?> +--FILE-- +getMessage(), "\n"; + } +} + +echo "-- negative still reports the plain message --\n"; +try { + var_dump(str_repeat('12', -1)); +} catch (ValueError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +echo "-- small enough to be a valid size_t: not rejected, allocation decides --\n"; +var_dump(str_repeat('1', $sizeMax)); +?> +--EXPECTF-- +-- wider than size_t: rejected before narrowing -- +ValueError: str_repeat(): Argument #2 ($times) must be less than or equal to %d +ValueError: str_repeat(): Argument #2 ($times) must be less than or equal to %d +ValueError: str_repeat(): Argument #2 ($times) must be less than or equal to %d +-- negative still reports the plain message -- +ValueError: str_repeat(): Argument #2 ($times) must be greater than or equal to 0 +-- small enough to be a valid size_t: not rejected, allocation decides -- + +Fatal error: Possible integer overflow in memory allocation (%s) in %s on line %d diff --git a/ext/standard/tests/strings/str_split_variation6.phpt b/ext/standard/tests/strings/str_split_variation6.phpt index a8c1bbf1a927..706f5033ef76 100644 --- a/ext/standard/tests/strings/str_split_variation6.phpt +++ b/ext/standard/tests/strings/str_split_variation6.phpt @@ -19,6 +19,8 @@ $values = array ( 0x1A, //hexadecimal number 2147483647, //max positive integer number -2147483648, //min negative integer + PHP_INT_MAX, + (2 ** (PHP_SYS_SIZE * 8 - 2) - 1 << 1) + 1, // SSIZE_MAX ); //loop through each element of $values for 'split_length' @@ -144,3 +146,13 @@ array(1) { } -- Iteration 7 -- str_split(): Argument #2 ($length) must be greater than 0 +-- Iteration 8 -- +array(1) { + [0]=> + string(42) "This is a string with 123 & escape char \t" +} +-- Iteration 9 -- +array(1) { + [0]=> + string(42) "This is a string with 123 & escape char \t" +} diff --git a/ext/standard/tests/strings/stripos_error.phpt b/ext/standard/tests/strings/stripos_error.phpt index a3e805a709f9..ce1ab1ee085e 100644 --- a/ext/standard/tests/strings/stripos_error.phpt +++ b/ext/standard/tests/strings/stripos_error.phpt @@ -11,6 +11,12 @@ try { echo $exception->getMessage() . "\n"; } +try { + stripos("Hello World", "o", PHP_INT_MAX); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + echo "\n-- Offset before the start of the string --\n"; try { stripos("Hello World", "o", -12); @@ -18,6 +24,12 @@ try { echo $exception->getMessage() . "\n"; } +try { + stripos("Hello World", "o", PHP_INT_MIN); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + echo "*** Done ***"; ?> --EXPECT-- @@ -25,7 +37,9 @@ echo "*** Done ***"; -- Offset beyond the end of the string -- stripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +stripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) -- Offset before the start of the string -- stripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +stripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) *** Done *** diff --git a/ext/standard/tests/strings/strpos_error.phpt b/ext/standard/tests/strings/strpos_error.phpt new file mode 100644 index 000000000000..d37344da68a3 --- /dev/null +++ b/ext/standard/tests/strings/strpos_error.phpt @@ -0,0 +1,45 @@ +--TEST-- +Test strpos() function : error conditions +--FILE-- +getMessage() . "\n"; +} + +try { + strpos("Hello World", "o", PHP_INT_MAX); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +echo "\n-- Offset before the start of the string --\n"; +try { + strpos("Hello World", "o", -12); +} catch (ValueError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + strpos("Hello World", "o", PHP_INT_MIN); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +echo "*** Done ***"; +?> +--EXPECT-- +*** Testing strpos() function: error conditions *** + +-- Offset beyond the end of the string -- +strpos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +strpos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) + +-- Offset before the start of the string -- +strpos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +strpos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +*** Done *** diff --git a/ext/standard/tests/strings/strripos_error.phpt b/ext/standard/tests/strings/strripos_error.phpt new file mode 100644 index 000000000000..4dccc461cfbb --- /dev/null +++ b/ext/standard/tests/strings/strripos_error.phpt @@ -0,0 +1,45 @@ +--TEST-- +Test strripos() function : error conditions +--FILE-- +getMessage() . "\n"; +} + +try { + strripos("Hello World", "o", PHP_INT_MAX); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +echo "\n-- Offset before the start of the string --\n"; +try { + strripos("Hello World", "o", -12); +} catch (ValueError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + strripos("Hello World", "o", PHP_INT_MIN); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +echo "*** Done ***"; +?> +--EXPECT-- +*** Testing strripos() function: error conditions *** + +-- Offset beyond the end of the string -- +strripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +strripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) + +-- Offset before the start of the string -- +strripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +strripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +*** Done *** diff --git a/ext/standard/tests/strings/strrpos_error.phpt b/ext/standard/tests/strings/strrpos_error.phpt new file mode 100644 index 000000000000..85206eddfd7f --- /dev/null +++ b/ext/standard/tests/strings/strrpos_error.phpt @@ -0,0 +1,45 @@ +--TEST-- +Test strrpos() function : error conditions +--FILE-- +getMessage() . "\n"; +} + +try { + strrpos("Hello World", "o", PHP_INT_MAX); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +echo "\n-- Offset before the start of the string --\n"; +try { + strrpos("Hello World", "o", -12); +} catch (ValueError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + strrpos("Hello World", "o", PHP_INT_MIN); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +echo "*** Done ***"; +?> +--EXPECT-- +*** Testing strrpos() function: error conditions *** + +-- Offset beyond the end of the string -- +strrpos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +strrpos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) + +-- Offset before the start of the string -- +strrpos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +strrpos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +*** Done *** diff --git a/ext/standard/tests/strings/substr.phpt b/ext/standard/tests/strings/substr.phpt index c870e1de0fbd..d3fb68e64bef 100644 --- a/ext/standard/tests/strings/substr.phpt +++ b/ext/standard/tests/strings/substr.phpt @@ -59,6 +59,16 @@ echo "\n*** Omitting length or using NULL length ***\n"; var_dump (substr("abcdef" , 2) ); var_dump (substr("abcdef" , 2, NULL) ); +/* Very big offset */ +echo "\n*** Very big offset ***\n"; +var_dump (substr("abcdef" , PHP_INT_MAX) ); +var_dump (substr("abcdef" , PHP_INT_MIN) ); + +/* Very big length */ +echo "\n*** Very big length ***\n"; +var_dump (substr("abcdef" , 0, PHP_INT_MAX) ); +var_dump (substr("abcdef" , 0, PHP_INT_MIN) ); + echo"\nDone"; ?> @@ -173,4 +183,12 @@ string(4) "abcd" string(4) "cdef" string(4) "cdef" +*** Very big offset *** +string(0) "" +string(6) "abcdef" + +*** Very big length *** +string(6) "abcdef" +string(0) "" + Done diff --git a/ext/standard/tests/strings/substr_compare.phpt b/ext/standard/tests/strings/substr_compare.phpt index 51d093a65fa2..995588940f42 100644 --- a/ext/standard/tests/strings/substr_compare.phpt +++ b/ext/standard/tests/strings/substr_compare.phpt @@ -13,13 +13,25 @@ var_dump(substr_compare("abcde", "cd", 1, 2) < 0); var_dump(substr_compare("abcde", "abc", 5, 1)); var_dump(substr_compare("abcde", "abcdef", -10, 10) < 0); var_dump(substr_compare("abcde", "abc", 0, 0)); +var_dump(substr_compare("abc", "abcde", 0, PHP_INT_MAX)); echo "Test\n"; +var_dump(substr_compare("abcde", "abc", 0)); +var_dump(substr_compare("abcde", "abc", -100)); +var_dump(substr_compare("abcde", "abc", -PHP_INT_MAX)); + try { - substr_compare("abcde", "abc", 0, -1); + var_dump(substr_compare("abcde", "abc", 0, -1)); } catch (\ValueError $e) { echo $e->getMessage() . "\n"; } + +try { + var_dump(substr_compare("abcde", "abc", 0, PHP_INT_MIN)); +} catch (\ValueError $e) { + echo $e->getMessage() . "\n"; +} + var_dump(substr_compare("abcde", "abc", -1, NULL, -5) > 0); ?> --EXPECT-- @@ -33,6 +45,11 @@ bool(true) int(-1) bool(true) int(0) +int(-1) Test +int(1) +int(1) +int(1) +substr_compare(): Argument #4 ($length) must be greater than or equal to 0 substr_compare(): Argument #4 ($length) must be greater than or equal to 0 bool(true) diff --git a/ext/standard/tests/strings/substr_count_error.phpt b/ext/standard/tests/strings/substr_count_error.phpt index dc0d3d9834eb..614547577eec 100644 --- a/ext/standard/tests/strings/substr_count_error.phpt +++ b/ext/standard/tests/strings/substr_count_error.phpt @@ -20,6 +20,21 @@ try { echo $exception->getMessage() . "\n"; } +/* offset very big */ +try { + substr_count($str, 'b', PHP_INT_MAX); + echo "unexpected success\n"; +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +try { + substr_count($str, 'b', PHP_INT_MIN); + echo "unexpected success\n"; +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + /* Using offset and length to go beyond the size of the string: Exception is expected, as length+offset > length of string */ try { @@ -35,6 +50,21 @@ try { echo $exception->getMessage() . "\n"; } +/* length very big */ +try { + substr_count($str, 'b', 0, PHP_INT_MAX); + echo "unexpected success\n"; +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +try { + substr_count($str, 'b', 0, PHP_INT_MIN); + echo "unexpected success\n"; +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + echo "Done\n"; ?> @@ -42,6 +72,10 @@ echo "Done\n"; *** Testing error conditions *** substr_count(): Argument #3 ($offset) must be contained in argument #1 ($haystack) substr_count(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +substr_count(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +substr_count(): Argument #3 ($offset) must be contained in argument #1 ($haystack) +substr_count(): Argument #4 ($length) must be contained in argument #1 ($haystack) +substr_count(): Argument #4 ($length) must be contained in argument #1 ($haystack) substr_count(): Argument #4 ($length) must be contained in argument #1 ($haystack) substr_count(): Argument #4 ($length) must be contained in argument #1 ($haystack) Done diff --git a/ext/standard/tests/strings/substr_replace_large_offset_length.phpt b/ext/standard/tests/strings/substr_replace_large_offset_length.phpt new file mode 100644 index 000000000000..c6cb329d1218 --- /dev/null +++ b/ext/standard/tests/strings/substr_replace_large_offset_length.phpt @@ -0,0 +1,39 @@ +--TEST-- +Test substr_replace() function : large offset & length +--FILE-- +getMessage(), "\n"; +} + +try { + var_dump(substr_replace('hello', 'X', PHP_INT_MIN)); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +echo "*** Very large length ***\n"; +try { + var_dump(substr_replace('hello', 'X', 0, PHP_INT_MAX)); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +try { + var_dump(substr_replace('hello', 'X', 0, PHP_INT_MIN)); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +*** Very large offset *** +string(6) "helloX" +string(1) "X" +*** Very large length *** +string(1) "X" +string(6) "Xhello" diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 82bfa8d38e33..13f1b0f9c3a3 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1608,7 +1608,7 @@ static ZEND_FUNCTION(zend_test_is_zend_ptr) Z_PARAM_LONG(addr); ZEND_PARSE_PARAMETERS_END(); - RETURN_BOOL(is_zend_ptr((void*)addr)); + RETURN_BOOL(is_zend_ptr((void*)(intptr_t)addr)); } static ZEND_FUNCTION(zend_test_log_err_debug) diff --git a/main/main.stub.php b/main/main.stub.php index af19a7f73731..56719a1b7904 100644 --- a/main/main.stub.php +++ b/main/main.stub.php @@ -171,6 +171,22 @@ * @cvalue SIZEOF_ZEND_LONG */ const PHP_INT_SIZE = UNKNOWN; +/** + * @var int + * @cvalue SIZEOF_SIZE_T + */ +const PHP_SYS_SIZE = UNKNOWN; +/** + * The greatest length a string can have. This is the allocator's limit + * (ZSTR_MAX_LEN) capped to what a zend_long can express, because every + * userland string length travels through zend_long: strlen()'s return value, + * string offsets and substr()'s arguments. Allocating a string anywhere near + * this will normally fail long before the limit itself is reached. + * + * @var int + * @cvalue (SIZEOF_SIZE_T < SIZEOF_ZEND_LONG ? (zend_long) ZSTR_MAX_LEN : ZEND_LONG_MAX) + */ +const PHP_STRING_MAX_LENGTH = UNKNOWN; /** * @var int * @cvalue FD_SETSIZE diff --git a/main/main_arginfo.h b/main/main_arginfo.h index 0da355e87b77..920878339476 100644 --- a/main/main_arginfo.h +++ b/main/main_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit main.stub.php instead. - * Stub hash: 22b4c7412680888c122886bccd21e3d38953ce33 */ + * Stub hash: 9cdeba665b44478182477d3c2a20fa7343833f69 */ #include "zend_constants.h" @@ -41,6 +41,8 @@ static void register_main_symbols(int module_number) REGISTER_LONG_CONSTANT("PHP_INT_MAX", ZEND_LONG_MAX, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_INT_MIN", ZEND_LONG_MIN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_INT_SIZE", SIZEOF_ZEND_LONG, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_SYS_SIZE", SIZEOF_SIZE_T, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_STRING_MAX_LENGTH", (SIZEOF_SIZE_T < SIZEOF_ZEND_LONG ? (zend_long) ZSTR_MAX_LEN : ZEND_LONG_MAX), CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_FD_SETSIZE", FD_SETSIZE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_FLOAT_DIG", DBL_DIG, CONST_PERSISTENT); REGISTER_DOUBLE_CONSTANT("PHP_FLOAT_EPSILON", DBL_EPSILON, CONST_PERSISTENT); diff --git a/main/streams/memory.c b/main/streams/memory.c index e76598ed0f46..ad3877f1e1b2 100644 --- a/main/streams/memory.c +++ b/main/streams/memory.c @@ -243,6 +243,8 @@ static int php_stream_memory_set_option(php_stream *stream, int option, int valu if (newsize < ms->fpos) { ms->fpos = newsize; } + } else if (UNEXPECTED(newsize > ZSTR_MAX_LEN)) { + return PHP_STREAM_OPTION_RETURN_ERR; } else { size_t old_size = ZSTR_LEN(ms->data); ms->data = zend_string_realloc(ms->data, newsize, 0); diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c index 1233f0430121..addd56ea454c 100644 --- a/sapi/phpdbg/phpdbg_bp.c +++ b/sapi/phpdbg/phpdbg_bp.c @@ -513,7 +513,7 @@ PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_o opline_break.disabled = 0; opline_break.hits = 0; opline_break.id = brake->id; - opline_break.opline = brake->opline = (zend_ulong)(op_array->opcodes + brake->opline_num); + opline_break.opline = brake->opline = ZEND_PTR_TO_ZEND_ULONG(op_array->opcodes + brake->opline_num); opline_break.name = NULL; opline_break.base = brake; if (op_array->scope) { @@ -809,7 +809,7 @@ PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline) /* { PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP; PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPLINE); - new_break.opline = (zend_ulong) opline; + new_break.opline = ZEND_PTR_TO_ZEND_ULONG(opline); new_break.base = NULL; zend_hash_index_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (zend_ulong)(uintptr_t) opline, &new_break, sizeof(phpdbg_breakline_t)); @@ -817,7 +817,7 @@ PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline) /* { phpdbg_notice("Breakpoint #%d added at #"ZEND_ULONG_FMT, new_break.id, new_break.opline); PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); } else { - phpdbg_error("Breakpoint exists for opline #"ZEND_ULONG_FMT, (zend_ulong) opline); + phpdbg_error("Breakpoint exists for opline #"ZEND_ULONG_FMT, ZEND_PTR_TO_ZEND_ULONG(opline)); } } /* }}} */ @@ -1068,7 +1068,7 @@ static inline bool phpdbg_find_breakpoint_param(phpdbg_param_t *param, zend_exec } break; case ADDR_PARAM: { - return ((zend_ulong)(phpdbg_opline_ptr_t)execute_data->opline == param->addr); + return (ZEND_PTR_TO_ZEND_ULONG((phpdbg_opline_ptr_t)execute_data->opline) == param->addr); } break; default: { diff --git a/sapi/phpdbg/phpdbg_btree.c b/sapi/phpdbg/phpdbg_btree.c index 788e9b464c14..5e58f63ce09c 100644 --- a/sapi/phpdbg/phpdbg_btree.c +++ b/sapi/phpdbg/phpdbg_btree.c @@ -253,7 +253,7 @@ void phpdbg_btree_branch_dump(phpdbg_btree_branch *branch, zend_ulong depth) { phpdbg_btree_branch_dump(branch->branches[0], depth); phpdbg_btree_branch_dump(branch->branches[1], depth); } else { - fprintf(stderr, "%p: %p\n", (void *) branch->result.idx, branch->result.ptr); + fprintf(stderr, ZEND_ULONG_FMT": %p\n", branch->result.idx, branch->result.ptr); } } } diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 88afd1b3752e..55d28b519752 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -1712,7 +1712,7 @@ void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */ /* perform seek operation */ if ((PHPDBG_G(flags) & PHPDBG_SEEK_MASK) && !(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { /* current address */ - zend_ulong address = (zend_ulong) execute_data->opline; + zend_ulong address = ZEND_PTR_TO_ZEND_ULONG(execute_data->opline); if (PHPDBG_G(seek_ex) != execute_data) { if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) { diff --git a/sapi/phpdbg/phpdbg_watch.c b/sapi/phpdbg/phpdbg_watch.c index a2e39e15a6ca..f8129515095b 100644 --- a/sapi/phpdbg/phpdbg_watch.c +++ b/sapi/phpdbg/phpdbg_watch.c @@ -226,7 +226,7 @@ void phpdbg_print_watch_diff(phpdbg_watchtype type, zend_string *name, void *old /* ### LOW LEVEL WATCHPOINT HANDLING ### */ static phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(phpdbg_btree *tree, void *addr) { phpdbg_watchpoint_t *watch; - phpdbg_btree_result *result = phpdbg_btree_find_closest(tree, (zend_ulong) phpdbg_get_page_boundary(addr) + phpdbg_pagesize - 1); + phpdbg_btree_result *result = phpdbg_btree_find_closest(tree, ZEND_PTR_TO_ZEND_ULONG(phpdbg_get_page_boundary(addr)) + phpdbg_pagesize - 1); if (result == NULL) { return NULL; @@ -343,14 +343,14 @@ void *phpdbg_watchpoint_userfaultfd_thread(void *phpdbg_globals_ptr) { /* ### REGISTER WATCHPOINT ### To be used only by watch element and collision managers ### */ static inline void phpdbg_store_watchpoint_btree(phpdbg_watchpoint_t *watch) { #if ZEND_DEBUG - phpdbg_btree_result *res = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) watch->addr.ptr); + phpdbg_btree_result *res = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), ZEND_PTR_TO_ZEND_ULONG(watch->addr.ptr)); ZEND_ASSERT(res == NULL || res->ptr == watch); #endif - phpdbg_btree_insert(&PHPDBG_G(watchpoint_tree), (zend_ulong) watch->addr.ptr, watch); + phpdbg_btree_insert(&PHPDBG_G(watchpoint_tree), ZEND_PTR_TO_ZEND_ULONG(watch->addr.ptr), watch); } static inline void phpdbg_remove_watchpoint_btree(phpdbg_watchpoint_t *watch) { - phpdbg_btree_delete(&PHPDBG_G(watchpoint_tree), (zend_ulong) watch->addr.ptr); + phpdbg_btree_delete(&PHPDBG_G(watchpoint_tree), ZEND_PTR_TO_ZEND_ULONG(watch->addr.ptr)); } /* ### SET WATCHPOINT ADDR ### To be used only by watch element and collision managers ### */ @@ -513,7 +513,7 @@ void phpdbg_watch_parent_ht(phpdbg_watch_element *element); static bool phpdbg_watch_element_collides(void *addr, phpdbg_watchtype type, phpdbg_watch_element *element) { phpdbg_watch_element *old; - phpdbg_btree_result *res = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) addr); + phpdbg_btree_result *res = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), ZEND_PTR_TO_ZEND_ULONG(addr)); if (res) { phpdbg_watchpoint_t *watch = res->ptr; @@ -544,7 +544,7 @@ phpdbg_watch_element *phpdbg_add_watch_element(phpdbg_watchpoint_t *watch, phpdb if (is_new) { *is_new = true; } - if ((res = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) watch->addr.ptr)) == NULL) { + if ((res = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), ZEND_PTR_TO_ZEND_ULONG(watch->addr.ptr))) == NULL) { phpdbg_watchpoint_t *mem = emalloc(sizeof(*mem)); *mem = *watch; watch = mem; @@ -728,12 +728,12 @@ void phpdbg_watch_parent_ht(phpdbg_watch_element *element) { phpdbg_btree_result *res; phpdbg_watch_ht_info *hti; ZEND_ASSERT(element->parent_container); - if (!(res = phpdbg_btree_find(&PHPDBG_G(watch_HashTables), (zend_ulong) element->parent_container))) { + if (!(res = phpdbg_btree_find(&PHPDBG_G(watch_HashTables), ZEND_PTR_TO_ZEND_ULONG(element->parent_container)))) { hti = emalloc(sizeof(*hti)); hti->ht = element->parent_container; zend_hash_init(&hti->watches, 0, NULL, ZVAL_PTR_DTOR, 0); - phpdbg_btree_insert(&PHPDBG_G(watch_HashTables), (zend_ulong) hti->ht, hti); + phpdbg_btree_insert(&PHPDBG_G(watch_HashTables), ZEND_PTR_TO_ZEND_ULONG(hti->ht), hti); phpdbg_set_addr_watchpoint(HT_GET_DATA_ADDR(hti->ht), HT_HASH_SIZE(hti->ht->nTableMask), &hti->hash_watch); hti->hash_watch.type = WATCH_ON_HASHDATA; @@ -751,7 +751,7 @@ void phpdbg_watch_parent_ht(phpdbg_watch_element *element) { void phpdbg_unwatch_parent_ht(phpdbg_watch_element *element) { if (element->flags & PHPDBG_WATCH_HT_REGISTERED) { - phpdbg_btree_result *res = phpdbg_btree_find(&PHPDBG_G(watch_HashTables), (zend_ulong) element->parent_container); + phpdbg_btree_result *res = phpdbg_btree_find(&PHPDBG_G(watch_HashTables), ZEND_PTR_TO_ZEND_ULONG(element->parent_container)); ZEND_ASSERT(element->parent_container); element->flags &= ~PHPDBG_WATCH_HT_REGISTERED; if (res) { @@ -759,7 +759,7 @@ void phpdbg_unwatch_parent_ht(phpdbg_watch_element *element) { if (zend_hash_num_elements(&hti->watches) == 1) { zend_hash_destroy(&hti->watches); - phpdbg_btree_delete(&PHPDBG_G(watch_HashTables), (zend_ulong) hti->ht); + phpdbg_btree_delete(&PHPDBG_G(watch_HashTables), ZEND_PTR_TO_ZEND_ULONG(hti->ht)); phpdbg_remove_watchpoint_btree(&hti->hash_watch); phpdbg_deactivate_watchpoint(&hti->hash_watch); efree(hti); @@ -1141,7 +1141,7 @@ void phpdbg_check_watchpoint(phpdbg_watchpoint_t *watch) { zval *zv; ZEND_HASH_MAP_FOREACH_PTR(&watch->elements, element) { if (element->flags & PHPDBG_WATCH_RECURSIVE) { - phpdbg_btree_result *res = phpdbg_btree_find(&PHPDBG_G(watch_HashTables), (zend_ulong) HT_WATCH_HT(watch)); + phpdbg_btree_result *res = phpdbg_btree_find(&PHPDBG_G(watch_HashTables), ZEND_PTR_TO_ZEND_ULONG(HT_WATCH_HT(watch))); phpdbg_watch_ht_info *hti = res ? res->ptr : NULL; ZEND_HASH_REVERSE_FOREACH_KEY_VAL(HT_WATCH_HT(watch), idx, str, zv) { @@ -1254,7 +1254,7 @@ void phpdbg_reenable_memory_watches(void) { res = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), page + phpdbg_pagesize - 1); if (res) { watch = res->ptr; - if ((char *) page < (char *) watch->addr.ptr + watch->size) { + if ((char *) ZEND_ULONG_TO_PTR(page) < (char *) watch->addr.ptr + watch->size) { #ifdef HAVE_USERFAULTFD_WRITEFAULT if (PHPDBG_G(watch_userfaultfd)) { struct uffdio_writeprotect protect = { @@ -1268,7 +1268,7 @@ void phpdbg_reenable_memory_watches(void) { } else #endif { - mprotect((void *) page, phpdbg_pagesize, PROT_READ); + mprotect(ZEND_ULONG_TO_PTR(page), phpdbg_pagesize, PROT_READ); } } } @@ -1301,7 +1301,7 @@ int phpdbg_print_changed_zvals(void) { } if ((res = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), page - 1))) { watch = res->ptr; - if ((char *) page < (char *) watch->addr.ptr + watch->size) { + if ((char *) ZEND_ULONG_TO_PTR(page) < (char *) watch->addr.ptr + watch->size) { phpdbg_check_watchpoint(watch); } } @@ -1328,7 +1328,7 @@ void phpdbg_watch_efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { /* only do expensive checks if there are any watches at all */ if (zend_hash_num_elements(&PHPDBG_G(watch_elements))) { - if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) ptr))) { + if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), ZEND_PTR_TO_ZEND_ULONG(ptr)))) { phpdbg_watchpoint_t *watch = result->ptr; if (watch->type != WATCH_ON_HASHDATA) { phpdbg_remove_watchpoint(watch); @@ -1348,7 +1348,7 @@ void phpdbg_watch_efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { } /* special case watchpoints as they aren't on ptr but on ptr + HT_WATCH_OFFSET */ - if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), HT_WATCH_OFFSET + (zend_ulong) ptr))) { + if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), HT_WATCH_OFFSET + ZEND_PTR_TO_ZEND_ULONG(ptr)))) { phpdbg_watchpoint_t *watch = result->ptr; if (watch->type == WATCH_ON_HASHTABLE) { phpdbg_remove_watchpoint(watch);