Skip to content

Commit 516e543

Browse files
committed
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.
1 parent 3f6a5c8 commit 516e543

File tree

5 files changed

+244
-0
lines changed

5 files changed

+244
-0
lines changed

TSRM/tsrm_win32.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,37 @@ static void tsrm_win32_dtor(tsrm_win32_globals *globals)
8686
}
8787
}/*}}}*/
8888

89+
/**
90+
* Converts Windows GetLastError() codes to POSIX errno values
91+
* @param win32_error
92+
*/
93+
static void tsrm_set_errno_from_win32_error(const DWORD win32_error)
94+
{/*{{{*/
95+
switch (win32_error) {
96+
case ERROR_ACCESS_DENIED:
97+
errno = EACCES;
98+
break;
99+
case ERROR_NOT_ENOUGH_MEMORY:
100+
case ERROR_OUTOFMEMORY:
101+
errno = ENOMEM;
102+
break;
103+
case ERROR_INVALID_PARAMETER:
104+
case ERROR_INVALID_HANDLE:
105+
errno = EINVAL;
106+
break;
107+
case ERROR_ALREADY_EXISTS:
108+
errno = EEXIST;
109+
break;
110+
case ERROR_FILE_NOT_FOUND:
111+
case ERROR_PATH_NOT_FOUND:
112+
errno = ENOENT;
113+
break;
114+
default:
115+
errno = EINVAL;
116+
break;
117+
}
118+
}/*}}}*/
119+
89120
TSRM_API void tsrm_win32_startup(void)
90121
{/*{{{*/
91122
#ifdef ZTS
@@ -651,6 +682,7 @@ TSRM_API int shmget(key_t key, size_t size, int flags)
651682
if (!shm_handle) {
652683
if (flags & IPC_CREAT) {
653684
if (size == 0 || size > SIZE_MAX - sizeof(shm->descriptor)) {
685+
errno = EINVAL;
654686
return -1;
655687
}
656688
size += sizeof(shm->descriptor);
@@ -665,11 +697,13 @@ TSRM_API int shmget(key_t key, size_t size, int flags)
665697
created = TRUE;
666698
}
667699
if (!shm_handle) {
700+
tsrm_set_errno_from_win32_error(GetLastError());
668701
return -1;
669702
}
670703
} else {
671704
if (flags & IPC_EXCL) {
672705
CloseHandle(shm_handle);
706+
errno = EEXIST;
673707
return -1;
674708
}
675709
}
@@ -690,6 +724,7 @@ TSRM_API int shmget(key_t key, size_t size, int flags)
690724
shm = shm_get(key, NULL);
691725
if (!shm) {
692726
CloseHandle(shm_handle);
727+
errno = ENOMEM;
693728
return -1;
694729
}
695730
shm->segment = shm_handle;
@@ -716,6 +751,7 @@ TSRM_API int shmget(key_t key, size_t size, int flags)
716751
}
717752
UnmapViewOfFile(shm->descriptor);
718753
shm->descriptor = NULL;
754+
errno = EINVAL;
719755
return -1;
720756
}
721757

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
shmop errno codes on Windows
3+
--EXTENSIONS--
4+
shmop
5+
--SKIPIF--
6+
<?php
7+
if (PHP_OS_FAMILY !== "Windows") die("skip for Windows only");
8+
?>
9+
--FILE--
10+
<?php
11+
$key = 0xABCDEF01;
12+
$shm1 = shmop_open($key, 'n', 0644, 1024);
13+
if ($shm1 !== false) {
14+
$shm2 = shmop_open($key, 'n', 0644, 1024);
15+
shmop_delete($shm1);
16+
}
17+
echo "done\n";
18+
?>
19+
--EXPECTF--
20+
Warning: shmop_open(): Unable to attach or create shared memory segment "File exists" in %s on line %d
21+
done
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
shmop Windows errno mapping
3+
--EXTENSIONS--
4+
shmop
5+
--SKIPIF--
6+
<?php
7+
if (PHP_OS_FAMILY !== "Windows") die("skip for Windows only");
8+
?>
9+
--FILE--
10+
<?php
11+
echo "EEXIST test:\n";
12+
$key = 0xEEEEEEEE;
13+
$shm1 = shmop_open($key, 'n', 0644, 512);
14+
if ($shm1 !== false) {
15+
$shm2 = shmop_open($key, 'n', 0644, 512);
16+
shmop_delete($shm1);
17+
}
18+
19+
echo "\nENOENT attach test:\n";
20+
$shm = shmop_open(0x99999999, 'a', 0644, 0);
21+
22+
echo "\nENOENT write test:\n";
23+
$shm = shmop_open(0x77777777, 'w', 0644, 0);
24+
25+
echo "\ndone\n";
26+
?>
27+
--EXPECTF--
28+
EEXIST test:
29+
30+
Warning: shmop_open(): Unable to attach or create shared memory segment "File exists" in %s on line %d
31+
32+
ENOENT attach test:
33+
34+
Warning: shmop_open(): Unable to attach or create shared memory segment "No such file or directory" in %s on line %d
35+
36+
ENOENT write test:
37+
38+
Warning: shmop_open(): Unable to attach or create shared memory segment "No such file or directory" in %s on line %d
39+
40+
done
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
shmop errno handling tests
3+
--EXTENSIONS--
4+
shmop
5+
--SKIPIF--
6+
<?php
7+
if (PHP_OS_FAMILY !== "Windows") die("skip for Windows only");
8+
?>
9+
--FILE--
10+
<?php
11+
$key = 0x12345678;
12+
$size = 1024;
13+
14+
echo "create segment: ";
15+
$shm1 = shmop_open($key, 'n', 0644, $size);
16+
if ($shm1 === false) {
17+
die("failed\n");
18+
}
19+
echo "ok\n";
20+
21+
echo "duplicate with IPC_EXCL: ";
22+
$shm2 = shmop_open($key, 'n', 0644, $size);
23+
if ($shm2 === false) {
24+
echo "ok\n";
25+
} else {
26+
echo "failed\n";
27+
shmop_delete($shm2);
28+
}
29+
shmop_delete($shm1);
30+
31+
echo "attach non-existent: ";
32+
$shm = shmop_open(0x99999999, 'a', 0644, 0);
33+
echo ($shm === false) ? "ok\n" : "failed\n";
34+
35+
echo "write mode non-existent: ";
36+
$shm = shmop_open(0x88888888, 'w', 0644, 0);
37+
echo ($shm === false) ? "ok\n" : "failed\n";
38+
39+
echo "create/attach/write sequence: ";
40+
$key = 0x45678901;
41+
$shm_c = shmop_open($key, 'c', 0644, 512);
42+
$shm_a = shmop_open($key, 'a', 0644, 0);
43+
$shm_w = shmop_open($key, 'w', 0644, 0);
44+
if ($shm_c && $shm_a && $shm_w) {
45+
$data = "test";
46+
$written = shmop_write($shm_w, $data, 0);
47+
$read = shmop_read($shm_a, 0, strlen($data));
48+
echo ($read === $data) ? "ok\n" : "failed\n";
49+
shmop_delete($shm_c);
50+
} else {
51+
echo "failed\n";
52+
}
53+
?>
54+
--EXPECTF--
55+
create segment: ok
56+
duplicate with IPC_EXCL:
57+
Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d
58+
ok
59+
attach non-existent:
60+
Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d
61+
ok
62+
write mode non-existent:
63+
Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d
64+
ok
65+
create/attach/write sequence: ok
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
--TEST--
2+
shmop error conditions on Windows
3+
--EXTENSIONS--
4+
shmop
5+
--SKIPIF--
6+
<?php
7+
if (PHP_OS_FAMILY !== "Windows") die("skip for Windows only");
8+
?>
9+
--FILE--
10+
<?php
11+
echo "duplicate segment: ";
12+
$key = 0xFEEDBEEF;
13+
$shm1 = shmop_open($key, 'n', 0644, 1024);
14+
$shm2 = shmop_open($key, 'n', 0644, 1024);
15+
echo ($shm1 && !$shm2) ? "ok\n" : "failed\n";
16+
shmop_delete($shm1);
17+
18+
echo "non-existent attach: ";
19+
$shm = shmop_open(0xDEADC0DE, 'a', 0644, 0);
20+
echo ($shm === false) ? "ok\n" : "failed\n";
21+
22+
echo "non-existent write: ";
23+
$shm = shmop_open(0xBADF00D, 'w', 0644, 0);
24+
echo ($shm === false) ? "ok\n" : "failed\n";
25+
26+
echo "zero size: ";
27+
try {
28+
shmop_open(0x12340000, 'n', 0644, 0);
29+
echo "failed\n";
30+
} catch (ValueError $e) {
31+
echo "ok\n";
32+
}
33+
34+
echo "write/read test: ";
35+
$key = 0xC0FFEE00;
36+
$shm_c = shmop_open($key, 'c', 0644, 1024);
37+
$shm_w = shmop_open($key, 'w', 0644, 0);
38+
$shm_a = shmop_open($key, 'a', 0644, 0);
39+
if ($shm_c && $shm_w && $shm_a) {
40+
$data = "test data";
41+
$written = shmop_write($shm_w, $data, 0);
42+
$read = shmop_read($shm_a, 0, strlen($data));
43+
echo ($read === $data) ? "ok\n" : "failed\n";
44+
shmop_delete($shm_c);
45+
} else {
46+
echo "failed\n";
47+
}
48+
49+
echo "multiple segments: ";
50+
$segments = [];
51+
for ($i = 0; $i < 3; $i++) {
52+
$shm = shmop_open(0xA0000000 + $i, 'c', 0644, 256);
53+
if ($shm) $segments[] = $shm;
54+
}
55+
echo (count($segments) === 3) ? "ok\n" : "failed\n";
56+
foreach ($segments as $shm) {
57+
shmop_delete($shm);
58+
}
59+
60+
echo "large segment: ";
61+
$shm = shmop_open(0xBEEF0000, 'n', 0644, 1024 * 1024);
62+
if ($shm) {
63+
echo (shmop_size($shm) >= 1024 * 1024) ? "ok\n" : "failed\n";
64+
shmop_delete($shm);
65+
} else {
66+
echo "failed\n";
67+
}
68+
?>
69+
--EXPECTF--
70+
duplicate segment:
71+
Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d
72+
ok
73+
non-existent attach:
74+
Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d
75+
ok
76+
non-existent write:
77+
Warning: shmop_open(): Unable to attach or create shared memory segment%s in %s on line %d
78+
ok
79+
zero size: ok
80+
write/read test: ok
81+
multiple segments: ok
82+
large segment: ok

0 commit comments

Comments
 (0)