Commit a72e0636fe4 for php.net
commit a72e0636fe423a7b32739d502a0c40582d157fc1
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Thu Jul 30 18:06:02 2026 -0400
ext/sysvshm: don't orphan the segment shm_attach() just created
When the key does not exist yet, shm_attach() creates the segment with
IPC_CREAT | IPC_EXCL and then attaches to it. If shmat() fails the
segment stays behind with no PHP handle able to remove it, and the
existence probe finds it on every later call, so a permission mask that
denies the caller wedges the key until ipcrm. Remove the segment on that
failure; IPC_EXCL makes the ownership flag exact, so one we opened
rather than created is never touched.
Closes GH-22959
diff --git a/ext/sysvshm/sysvshm.c b/ext/sysvshm/sysvshm.c
index 3fa7c77add3..84c10add85e 100644
--- a/ext/sysvshm/sysvshm.c
+++ b/ext/sysvshm/sysvshm.c
@@ -132,6 +132,7 @@ PHP_FUNCTION(shm_attach)
sysvshm_chunk_head *chunk_ptr;
zend_long shm_key, shm_id, shm_size, shm_flag = 0666;
bool shm_size_is_null = 1;
+ bool created = false;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|l!l", &shm_key, &shm_size, &shm_size_is_null, &shm_flag)) {
RETURN_THROWS();
@@ -156,10 +157,14 @@ PHP_FUNCTION(shm_attach)
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key, strerror(errno));
RETURN_FALSE;
}
+ created = true;
}
if ((shm_ptr = shmat(shm_id, NULL, 0)) == (void *) -1) {
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key, strerror(errno));
+ if (created) {
+ shmctl(shm_id, IPC_RMID, NULL);
+ }
RETURN_FALSE;
}
diff --git a/ext/sysvshm/tests/shm_attach_failed_attach.phpt b/ext/sysvshm/tests/shm_attach_failed_attach.phpt
new file mode 100644
index 00000000000..34b3261a246
--- /dev/null
+++ b/ext/sysvshm/tests/shm_attach_failed_attach.phpt
@@ -0,0 +1,34 @@
+--TEST--
+shm_attach() removes the segment it created when shmat() fails
+--EXTENSIONS--
+sysvshm
+posix
+--SKIPIF--
+<?php
+if (posix_geteuid() === 0) die('skip cannot run as root');
+?>
+--FILE--
+<?php
+$key = ftok(__FILE__, 't');
+
+var_dump(shm_attach($key, 1024, 0));
+
+$segment = shm_attach($key, 1024, 0600);
+
+if (!$segment instanceof SysvSharedMemory) {
+ die("the key is still held by the segment of the failed attach\n");
+}
+
+try {
+ var_dump(shm_put_var($segment, 1, 'value'));
+ var_dump(shm_get_var($segment, 1));
+} finally {
+ var_dump(shm_remove($segment));
+}
+?>
+--EXPECTF--
+Warning: shm_attach(): Failed for key 0x%x: %s in %s on line %d
+bool(false)
+bool(true)
+string(5) "value"
+bool(true)