diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index 4c8fc9d19aa9a..ec385596814ed 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; } @@ -744,6 +780,7 @@ TSRM_API int shmdt(const void *shmaddr) int ret; if (!shm || !shm->segment) { + errno = EINVAL; return -1; } @@ -753,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; @@ -764,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; } @@ -782,10 +823,16 @@ 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; default: + 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