From 3f6a5c8a76764dcea9872fee5beed8fa7d1d5bcd Mon Sep 17 00:00:00 2001 From: Volker Dusch Date: Tue, 16 Dec 2025 16:59:07 +0100 Subject: [PATCH 1/4] Update versions for PHP 8.5.1 --- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Zend/zend.h b/Zend/zend.h index e2e500022a85e..08ee5f89d4619 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.5.1-dev" +#define ZEND_VERSION "4.5.1" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index f81d8cf609054..49f0fd191a205 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.5.1-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.5.1],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/main/php_version.h b/main/php_version.h index 87cf375f2e0f9..774a31a7d8f53 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -3,6 +3,6 @@ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 5 #define PHP_RELEASE_VERSION 1 -#define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.5.1-dev" +#define PHP_EXTRA_VERSION "" +#define PHP_VERSION "8.5.1" #define PHP_VERSION_ID 80501 From 516e5438dc6343adda955c8de4bb6506ba3b9d88 Mon Sep 17 00:00:00 2001 From: Edmond <1571649+edmonddantes@users.noreply.github.com> Date: Thu, 15 Jan 2026 09:57:05 +0000 Subject: [PATCH 2/4] Fix shmop errno handling on Windows Add proper errno setting for all error paths in shmget() on Windows. Introduces tsrm_set_errno_from_win32_error() to map Windows error codes to POSIX errno values (EACCES, ENOMEM, EINVAL, EEXIST, ENOENT). This ensures that shmop_open() can provide meaningful error messages to users instead of "No error" when operations fail. Tests added to verify errno mapping for different error conditions. --- TSRM/tsrm_win32.c | 36 ++++++++ ext/shmop/tests/shmop_errno_codes_win32.phpt | 21 +++++ .../tests/shmop_errno_mapping_win32.phpt | 40 +++++++++ ext/shmop/tests/shmop_errno_tests.phpt | 65 +++++++++++++++ .../tests/shmop_error_conditions_win32.phpt | 82 +++++++++++++++++++ 5 files changed, 244 insertions(+) create mode 100644 ext/shmop/tests/shmop_errno_codes_win32.phpt create mode 100644 ext/shmop/tests/shmop_errno_mapping_win32.phpt create mode 100644 ext/shmop/tests/shmop_errno_tests.phpt create mode 100644 ext/shmop/tests/shmop_error_conditions_win32.phpt diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index 4c8fc9d19aa9a..c06d670632f2d 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -86,6 +86,37 @@ static void tsrm_win32_dtor(tsrm_win32_globals *globals) } }/*}}}*/ +/** + * Converts Windows GetLastError() codes to POSIX errno values + * @param win32_error + */ +static void tsrm_set_errno_from_win32_error(const DWORD win32_error) +{/*{{{*/ + switch (win32_error) { + case ERROR_ACCESS_DENIED: + errno = EACCES; + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_OUTOFMEMORY: + errno = ENOMEM; + break; + case ERROR_INVALID_PARAMETER: + case ERROR_INVALID_HANDLE: + errno = EINVAL; + break; + case ERROR_ALREADY_EXISTS: + errno = EEXIST; + break; + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + errno = ENOENT; + break; + default: + errno = EINVAL; + break; + } +}/*}}}*/ + TSRM_API void tsrm_win32_startup(void) {/*{{{*/ #ifdef ZTS @@ -651,6 +682,7 @@ TSRM_API int shmget(key_t key, size_t size, int flags) if (!shm_handle) { if (flags & IPC_CREAT) { if (size == 0 || size > SIZE_MAX - sizeof(shm->descriptor)) { + errno = EINVAL; return -1; } size += sizeof(shm->descriptor); @@ -665,11 +697,13 @@ TSRM_API int shmget(key_t key, size_t size, int flags) created = TRUE; } if (!shm_handle) { + tsrm_set_errno_from_win32_error(GetLastError()); return -1; } } else { if (flags & IPC_EXCL) { CloseHandle(shm_handle); + errno = EEXIST; return -1; } } @@ -690,6 +724,7 @@ TSRM_API int shmget(key_t key, size_t size, int flags) shm = shm_get(key, NULL); if (!shm) { CloseHandle(shm_handle); + errno = ENOMEM; return -1; } shm->segment = shm_handle; @@ -716,6 +751,7 @@ TSRM_API int shmget(key_t key, size_t size, int flags) } UnmapViewOfFile(shm->descriptor); shm->descriptor = NULL; + errno = EINVAL; return -1; } diff --git a/ext/shmop/tests/shmop_errno_codes_win32.phpt b/ext/shmop/tests/shmop_errno_codes_win32.phpt new file mode 100644 index 0000000000000..410571563f26e --- /dev/null +++ b/ext/shmop/tests/shmop_errno_codes_win32.phpt @@ -0,0 +1,21 @@ +--TEST-- +shmop errno codes on Windows +--EXTENSIONS-- +shmop +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: shmop_open(): Unable to attach or create shared memory segment "File exists" in %s on line %d +done diff --git a/ext/shmop/tests/shmop_errno_mapping_win32.phpt b/ext/shmop/tests/shmop_errno_mapping_win32.phpt new file mode 100644 index 0000000000000..7c8f57ea1b7c5 --- /dev/null +++ b/ext/shmop/tests/shmop_errno_mapping_win32.phpt @@ -0,0 +1,40 @@ +--TEST-- +shmop Windows errno mapping +--EXTENSIONS-- +shmop +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +EEXIST test: + +Warning: shmop_open(): Unable to attach or create shared memory segment "File exists" in %s on line %d + +ENOENT attach test: + +Warning: shmop_open(): Unable to attach or create shared memory segment "No such file or directory" in %s on line %d + +ENOENT write test: + +Warning: shmop_open(): Unable to attach or create shared memory segment "No such file or directory" in %s on line %d + +done diff --git a/ext/shmop/tests/shmop_errno_tests.phpt b/ext/shmop/tests/shmop_errno_tests.phpt new file mode 100644 index 0000000000000..da80c26b8476d --- /dev/null +++ b/ext/shmop/tests/shmop_errno_tests.phpt @@ -0,0 +1,65 @@ +--TEST-- +shmop errno handling tests +--EXTENSIONS-- +shmop +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +create segment: ok +duplicate with IPC_EXCL: +Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d +ok +attach non-existent: +Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d +ok +write mode non-existent: +Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d +ok +create/attach/write sequence: ok diff --git a/ext/shmop/tests/shmop_error_conditions_win32.phpt b/ext/shmop/tests/shmop_error_conditions_win32.phpt new file mode 100644 index 0000000000000..d60ad74dc5351 --- /dev/null +++ b/ext/shmop/tests/shmop_error_conditions_win32.phpt @@ -0,0 +1,82 @@ +--TEST-- +shmop error conditions on Windows +--EXTENSIONS-- +shmop +--SKIPIF-- + +--FILE-- += 1024 * 1024) ? "ok\n" : "failed\n"; + shmop_delete($shm); +} else { + echo "failed\n"; +} +?> +--EXPECTF-- +duplicate segment: +Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d +ok +non-existent attach: +Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d +ok +non-existent write: +Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d +ok +zero size: ok +write/read test: ok +multiple segments: ok +large segment: ok From 04f3226a16b588ee58ef10a1e31efa98262ec35a Mon Sep 17 00:00:00 2001 From: Edmond <1571649+edmonddantes@users.noreply.github.com> Date: Thu, 15 Jan 2026 10:10:33 +0000 Subject: [PATCH 3/4] Add errno handling to shmdt() and shmctl() on Windows Set errno for error conditions in shmdt() and shmctl(): - EINVAL for invalid segment address/key - Windows error mapping for UnmapViewOfFile failures - EINVAL for unknown shmctl commands This completes errno handling for all shmop system calls on Windows. --- TSRM/tsrm_win32.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index c06d670632f2d..91a4af1d0ee7d 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -780,6 +780,7 @@ TSRM_API int shmdt(const void *shmaddr) int ret; if (!shm || !shm->segment) { + errno = EINVAL; return -1; } @@ -789,7 +790,10 @@ TSRM_API int shmdt(const void *shmaddr) ret = 0; if (shm->descriptor->shm_nattch <= 0) { - ret = UnmapViewOfFile(shm->descriptor) ? 0 : -1; + if (!UnmapViewOfFile(shm->descriptor)) { + tsrm_set_errno_from_win32_error(GetLastError()); + ret = -1; + } shm->descriptor = NULL; } return ret; @@ -800,6 +804,7 @@ TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) shm_pair *shm = shm_get(key, NULL); if (!shm || !shm->segment) { + errno = EINVAL; return -1; } @@ -822,6 +827,7 @@ TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) return 0; default: + errno = EINVAL; return -1; } }/*}}}*/ From f7cb5371b624ba88e5780cb3db42a8f1b4f99f71 Mon Sep 17 00:00:00 2001 From: Edmond <1571649+edmonddantes@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:16:52 +0000 Subject: [PATCH 4/4] Fix Windows shared memory segment cleanup in shmctl IPC_RMID Add proper handle cleanup when marking shared memory segment for deletion. Previously, shmctl(IPC_RMID) only marked the segment by setting key to -1 but did not close the Windows file mapping handle, causing the segment to persist in the system. This led to errors when trying to reopen segments with the same key: - Segment remained accessible via OpenFileMapping() - But had key = -1, failing validation checks - Resulted in "Invalid argument" errors Now properly closes the handle, allowing Windows to destroy the named mapping object when no processes are attached, matching POSIX semantics where IPC_RMID marks segment for deletion. Fixes issue where shmop_open() with 'c' flag fails after shmop_delete(). --- TSRM/tsrm_win32.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index 91a4af1d0ee7d..ec385596814ed 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -823,6 +823,11 @@ TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) case IPC_RMID: if (shm->descriptor->shm_nattch < 1) { shm->descriptor->shm_perm.key = -1; + /* Close handle to allow Windows to destroy the named mapping object */ + if (shm->segment && shm->segment != INVALID_HANDLE_VALUE) { + CloseHandle(shm->segment); + shm->segment = INVALID_HANDLE_VALUE; + } } return 0;