From d2ca4711144a4087ddf4f08d9de43eb1f823768e Mon Sep 17 00:00:00 2001 From: Petr Sumbera Date: Tue, 16 Dec 2025 14:39:43 +0100 Subject: [PATCH 1/4] Increase SEG_ALLOC_SIZE_MAX to 64MB to support OPcache JIT on Solaris The SysV shared memory allocator in OPcache hardcodes a maximum segment size of 32MB (SEG_ALLOC_SIZE_MAX). With JIT enabled, OPcache reserves 64MB (ZEND_JIT_DEFAULT_BUFFER_SIZE) from the last segment, causing startup to fail with "Insufficient shared memory!". This patch increases SEG_ALLOC_SIZE_MAX to 64MB so the reserved JIT buffer fits in a single segment. Behavior on other platforms using mmap remains unaffected. Fixes #20718. --- ext/opcache/shared_alloc_shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opcache/shared_alloc_shm.c b/ext/opcache/shared_alloc_shm.c index 09a357d189ed4..5c7c127722fe5 100644 --- a/ext/opcache/shared_alloc_shm.c +++ b/ext/opcache/shared_alloc_shm.c @@ -42,7 +42,7 @@ # define MIN(x, y) ((x) > (y)? (y) : (x)) #endif -#define SEG_ALLOC_SIZE_MAX 32*1024*1024 +#define SEG_ALLOC_SIZE_MAX 64*1024*1024 /* 64MB to match ZEND_JIT_DEFAULT_BUFFER_SIZE */ #define SEG_ALLOC_SIZE_MIN 2*1024*1024 typedef struct { From d29a4a9788fa29fc9e00ac1db1457ad13f952eac Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 4 Feb 2026 16:39:01 +0100 Subject: [PATCH 2/4] Improve shared_alloc_shm.c strategy Try allocating a contiguous buffer first, and only then use segmentation. Segmentation breaks the JIT, so a contiguous buffer is preferable. --- ext/opcache/shared_alloc_shm.c | 43 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/ext/opcache/shared_alloc_shm.c b/ext/opcache/shared_alloc_shm.c index 5c7c127722fe5..e9c1c0b8704c6 100644 --- a/ext/opcache/shared_alloc_shm.c +++ b/ext/opcache/shared_alloc_shm.c @@ -42,7 +42,6 @@ # define MIN(x, y) ((x) > (y)? (y) : (x)) #endif -#define SEG_ALLOC_SIZE_MAX 64*1024*1024 /* 64MB to match ZEND_JIT_DEFAULT_BUFFER_SIZE */ #define SEG_ALLOC_SIZE_MIN 2*1024*1024 typedef struct { @@ -53,36 +52,38 @@ typedef struct { static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, const char **error_in) { int i; - size_t allocate_size = 0, remaining_bytes = requested_size, seg_allocate_size; + size_t allocate_size = 0, remaining_bytes, seg_allocate_size; int first_segment_id = -1; key_t first_segment_key = -1; struct shmid_ds sds; int shmget_flags; zend_shared_segment_shm *shared_segments; - seg_allocate_size = SEG_ALLOC_SIZE_MAX; - /* determine segment size we _really_ need: - * no more than to include requested_size - */ - while (requested_size * 2 <= seg_allocate_size && seg_allocate_size > SEG_ALLOC_SIZE_MIN) { - seg_allocate_size >>= 1; - } - shmget_flags = IPC_CREAT|SHM_R|SHM_W|IPC_EXCL; - /* try allocating this much, if not - try shrinking */ - while (seg_allocate_size >= SEG_ALLOC_SIZE_MIN) { - allocate_size = MIN(requested_size, seg_allocate_size); - first_segment_id = shmget(first_segment_key, allocate_size, shmget_flags); - if (first_segment_id != -1) { - break; + /* Try contiguous allocation first. */ + seg_allocate_size = requested_size; + first_segment_id = shmget(first_segment_key, seg_allocate_size, shmget_flags); + if (UNEXPECTED(first_segment_id == -1)) { + /* Search for power of n^2 < requested_size. */ + seg_allocate_size = 1024 * 1024; + while (seg_allocate_size < requested_size / 2) { + seg_allocate_size *= 2; } - seg_allocate_size >>= 1; /* shrink the allocated block */ - } - if (first_segment_id == -1) { - *error_in = "shmget"; - return ALLOC_FAILURE; + /* try allocating this much, if not - try shrinking */ + while (seg_allocate_size >= SEG_ALLOC_SIZE_MIN) { + first_segment_id = shmget(first_segment_key, seg_allocate_size, shmget_flags); + if (first_segment_id != -1) { + break; + } + seg_allocate_size >>= 1; /* shrink the allocated block */ + } + + if (first_segment_id == -1) { + *error_in = "shmget"; + return ALLOC_FAILURE; + } } *shared_segments_count = ((requested_size - 1) / seg_allocate_size) + 1; From deaf7c871b34d7d4475361b88af6449d5c969362 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 4 Feb 2026 16:45:24 +0100 Subject: [PATCH 3/4] Fix comment --- ext/opcache/shared_alloc_shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opcache/shared_alloc_shm.c b/ext/opcache/shared_alloc_shm.c index e9c1c0b8704c6..7f4f518d1a9d5 100644 --- a/ext/opcache/shared_alloc_shm.c +++ b/ext/opcache/shared_alloc_shm.c @@ -65,7 +65,7 @@ static int create_segments(size_t requested_size, zend_shared_segment_shm ***sha seg_allocate_size = requested_size; first_segment_id = shmget(first_segment_key, seg_allocate_size, shmget_flags); if (UNEXPECTED(first_segment_id == -1)) { - /* Search for power of n^2 < requested_size. */ + /* Search for biggest n^2 < requested_size. */ seg_allocate_size = 1024 * 1024; while (seg_allocate_size < requested_size / 2) { seg_allocate_size *= 2; From 8bc4209910e9fc7bc02dec599bf963c2dc21f7b4 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 5 Feb 2026 14:40:50 +0100 Subject: [PATCH 4/4] Use SEG_ALLOC_SIZE_MIN instead of hard-coded start value --- ext/opcache/shared_alloc_shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opcache/shared_alloc_shm.c b/ext/opcache/shared_alloc_shm.c index 7f4f518d1a9d5..b9f8ca4524a05 100644 --- a/ext/opcache/shared_alloc_shm.c +++ b/ext/opcache/shared_alloc_shm.c @@ -66,7 +66,7 @@ static int create_segments(size_t requested_size, zend_shared_segment_shm ***sha first_segment_id = shmget(first_segment_key, seg_allocate_size, shmget_flags); if (UNEXPECTED(first_segment_id == -1)) { /* Search for biggest n^2 < requested_size. */ - seg_allocate_size = 1024 * 1024; + seg_allocate_size = SEG_ALLOC_SIZE_MIN; while (seg_allocate_size < requested_size / 2) { seg_allocate_size *= 2; }