Skip to content

Commit d23d05b

Browse files
committed
fix: invalid opcache SHM initialization
1 parent e7ce542 commit d23d05b

3 files changed

Lines changed: 199 additions & 105 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
OPcache starts with default static cache memory and tracing JIT
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.enable=1
7+
opcache.enable_cli=1
8+
opcache.jit=tracing
9+
opcache.jit_buffer_size=64M
10+
opcache.protect_memory=1
11+
--FILE--
12+
<?php
13+
14+
$config = opcache_get_configuration();
15+
$status = opcache_get_status(false);
16+
17+
var_dump($config['directives']['opcache.static_cache.volatile_size_mb']);
18+
var_dump($config['directives']['opcache.static_cache.pinned_size_mb']);
19+
var_dump($status['volatile_cache']->enabled);
20+
var_dump($status['pinned_cache']->enabled);
21+
echo "OK\n";
22+
23+
?>
24+
--EXPECT--
25+
int(8388608)
26+
int(8388608)
27+
bool(true)
28+
bool(true)
29+
OK

ext/opcache/zend_static_cache.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,10 @@ static zend_result zend_opcache_static_cache_rinit(void)
12661266
zend_result zend_opcache_static_cache_rshutdown(void)
12671267
{
12681268
zend_opcache_static_cache_clear_lookup_caches();
1269+
1270+
EG(static_cache_class_access_active) = false;
1271+
EG(tracked_mutation_hooks_active) = false;
1272+
12691273
zend_opcache_static_cache_request_shutdown();
12701274
zend_opcache_static_cache_release_request_entry_locks();
12711275
zend_opcache_static_cache_release_request_local_slots();

ext/opcache/zend_static_cache_storage.c

Lines changed: 166 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,99 @@
3535
# ifdef HAVE_UNISTD_H
3636
# include <unistd.h>
3737
# endif
38-
# if defined(__linux__) && defined(HAVE_MEMFD_CREATE)
38+
# if defined(USE_MMAP) || (defined(__linux__) && defined(HAVE_MEMFD_CREATE))
3939
# include <sys/mman.h>
4040
# endif
4141
#endif
4242

43+
#if defined(USE_MMAP) && !defined(ZEND_WIN32)
44+
# if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
45+
# define MAP_ANONYMOUS MAP_ANON
46+
# endif
47+
48+
static zend_always_inline bool zend_opcache_static_cache_force_startup_failure(void)
49+
{
50+
const char *value = getenv("OPCACHE_STATIC_CACHE_FORCE_STARTUP_FAILURE");
51+
52+
return value != NULL && value[0] != '\0' && value[0] != '0';
53+
}
54+
55+
static zend_always_inline bool zend_opcache_static_cache_requires_pre_request_storage(void)
56+
{
57+
return sapi_module.name != NULL && strcmp(sapi_module.name, "fpm-fcgi") == 0;
58+
}
59+
60+
static zend_always_inline void zend_opcache_static_cache_set_unavailable(const char *failure_reason, bool startup_failed)
61+
{
62+
zend_opcache_static_cache_context *context = zend_opcache_static_cache_active_context();
63+
zend_opcache_static_cache_runtime *runtime = zend_opcache_static_cache_context_runtime(context);
64+
65+
runtime->available = false;
66+
runtime->startup_failed = startup_failed;
67+
runtime->backend_initialized = context->storage.initialized;
68+
runtime->failure_reason = failure_reason;
69+
}
70+
71+
static zend_always_inline void zend_opcache_static_cache_set_available(void)
72+
{
73+
zend_opcache_static_cache_context *context = zend_opcache_static_cache_active_context();
74+
zend_opcache_static_cache_runtime *runtime = zend_opcache_static_cache_context_runtime(context);
75+
76+
runtime->available = true;
77+
runtime->startup_failed = false;
78+
runtime->backend_initialized = context->storage.initialized;
79+
runtime->failure_reason = NULL;
80+
}
81+
82+
static zend_always_inline HashTable **zend_opcache_static_cache_entry_locks_ptr_for_context(zend_opcache_static_cache_context *context)
83+
{
84+
return context == &zend_opcache_static_cache_pinned_context_state
85+
? &zend_opcache_static_cache_pinned_entry_locks
86+
: &zend_opcache_static_cache_volatile_entry_locks
87+
;
88+
}
89+
90+
static zend_always_inline uint32_t *zend_opcache_static_cache_entry_lock_counts_for_context(zend_opcache_static_cache_context *context)
91+
{
92+
return context == &zend_opcache_static_cache_pinned_context_state
93+
? zend_opcache_static_cache_pinned_entry_lock_counts
94+
: zend_opcache_static_cache_volatile_entry_lock_counts
95+
;
96+
}
97+
98+
static zend_always_inline uint32_t zend_opcache_static_cache_entry_lock_stripe(zend_string *key)
99+
{
100+
return (uint32_t) (zend_string_hash_val(key) % ZEND_OPCACHE_STATIC_CACHE_ENTRY_LOCK_STRIPES);
101+
}
102+
103+
static zend_always_inline uint32_t zend_opcache_static_cache_used_end_offset_locked(const zend_opcache_static_cache_header *header)
104+
{
105+
return header->data_offset + header->next_free;
106+
}
107+
108+
static zend_always_inline bool zend_opcache_static_cache_payload_size_to_block_size(size_t size, uint32_t *block_size)
109+
{
110+
size_t aligned_size;
111+
112+
if (size == 0 || size > UINT32_MAX - sizeof(zend_opcache_static_cache_block)) {
113+
return false;
114+
}
115+
116+
aligned_size = ZEND_ALIGNED_SIZE(sizeof(zend_opcache_static_cache_block) + size);
117+
if (aligned_size > UINT32_MAX) {
118+
return false;
119+
}
120+
121+
*block_size = (uint32_t) aligned_size;
122+
123+
return true;
124+
}
125+
126+
static zend_always_inline bool zend_opcache_static_cache_offset_in_block(uint32_t offset, uint32_t block_offset, uint32_t block_size)
127+
{
128+
return offset >= block_offset + sizeof(zend_opcache_static_cache_block) && offset < block_offset + block_size;
129+
}
130+
43131
#ifdef ZEND_WIN32
44132
# define ZEND_OPCACHE_STATIC_CACHE_WIN32_MAPPING_PREFIX_SIZE (2 * sizeof(void *))
45133
# define ZEND_OPCACHE_STATIC_CACHE_WIN32_MAPPING_NAME "ZendOPcache.StaticCache.SharedMemoryArea"
@@ -53,6 +141,80 @@ typedef struct _zend_opcache_static_cache_win32_segment {
53141
size_t mapping_size;
54142
} zend_opcache_static_cache_win32_segment;
55143

144+
static inline bool zend_opcache_static_cache_win32_set_segment(
145+
zend_opcache_static_cache_win32_segment *segment,
146+
HANDLE memfile,
147+
void *mapping_base,
148+
size_t mapping_size,
149+
size_t requested_size
150+
)
151+
{
152+
segment->memfile = memfile;
153+
segment->mapping_base = mapping_base;
154+
segment->mapping_size = mapping_size;
155+
segment->segment.p = (char *) mapping_base + ZEND_OPCACHE_STATIC_CACHE_WIN32_MAPPING_PREFIX_SIZE;
156+
segment->segment.pos = 0;
157+
segment->segment.size = requested_size;
158+
159+
return true;
160+
}
161+
#endif
162+
163+
static int zend_opcache_static_cache_mmap_create_segments(
164+
size_t requested_size,
165+
zend_shared_segment ***shared_segments_p,
166+
int *shared_segments_count,
167+
const char **error_in
168+
)
169+
{
170+
zend_shared_segment *segment;
171+
void *mapping;
172+
173+
mapping = mmap(NULL, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
174+
if (mapping == MAP_FAILED) {
175+
*error_in = "mmap";
176+
return ALLOC_FAILURE;
177+
}
178+
179+
*shared_segments_count = 1;
180+
*shared_segments_p = (zend_shared_segment **) calloc(1, sizeof(zend_shared_segment *) + sizeof(zend_shared_segment));
181+
if (*shared_segments_p == NULL) {
182+
munmap(mapping, requested_size);
183+
*error_in = "calloc";
184+
return ALLOC_FAILURE;
185+
}
186+
187+
segment = (zend_shared_segment *) ((char *) *shared_segments_p + sizeof(zend_shared_segment *));
188+
(*shared_segments_p)[0] = segment;
189+
190+
segment->p = mapping;
191+
segment->pos = 0;
192+
segment->size = requested_size;
193+
segment->end = requested_size;
194+
195+
return ALLOC_SUCCESS;
196+
}
197+
198+
static int zend_opcache_static_cache_mmap_detach_segment(zend_shared_segment *shared_segment)
199+
{
200+
munmap(shared_segment->p, shared_segment->size);
201+
202+
return 0;
203+
}
204+
205+
static size_t zend_opcache_static_cache_mmap_segment_type_size(void)
206+
{
207+
return sizeof(zend_shared_segment);
208+
}
209+
210+
static const zend_shared_memory_handlers zend_opcache_static_cache_mmap_handlers = {
211+
zend_opcache_static_cache_mmap_create_segments,
212+
zend_opcache_static_cache_mmap_detach_segment,
213+
zend_opcache_static_cache_mmap_segment_type_size
214+
};
215+
#endif
216+
217+
#ifdef ZEND_WIN32
56218
static void zend_opcache_static_cache_win32_create_name(char *buffer, size_t buffer_size, const char *name, size_t unique_id)
57219
{
58220
zend_opcache_static_cache_context *context = zend_opcache_static_cache_active_context();
@@ -71,24 +233,6 @@ static void zend_opcache_static_cache_win32_create_name(char *buffer, size_t buf
71233
);
72234
}
73235

74-
static bool zend_opcache_static_cache_win32_set_segment(
75-
zend_opcache_static_cache_win32_segment *segment,
76-
HANDLE memfile,
77-
void *mapping_base,
78-
size_t mapping_size,
79-
size_t requested_size
80-
)
81-
{
82-
segment->memfile = memfile;
83-
segment->mapping_base = mapping_base;
84-
segment->mapping_size = mapping_size;
85-
segment->segment.p = (char *) mapping_base + ZEND_OPCACHE_STATIC_CACHE_WIN32_MAPPING_PREFIX_SIZE;
86-
segment->segment.pos = 0;
87-
segment->segment.size = requested_size;
88-
89-
return true;
90-
}
91-
92236
static int zend_opcache_static_cache_win32_reattach_segment(
93237
zend_opcache_static_cache_win32_segment *segment,
94238
HANDLE memfile,
@@ -357,8 +501,8 @@ static const zend_shared_memory_handlers zend_opcache_static_cache_win32_handler
357501
#endif
358502

359503
static const zend_shared_memory_handler_entry zend_opcache_static_cache_handler_table[] = {
360-
#ifdef USE_MMAP
361-
{ "mmap", &zend_alloc_mmap_handlers },
504+
#if defined(USE_MMAP) && !defined(ZEND_WIN32)
505+
{ "mmap", &zend_opcache_static_cache_mmap_handlers },
362506
#endif
363507
#ifdef USE_SHM
364508
{ "shm", &zend_alloc_shm_handlers },
@@ -379,41 +523,7 @@ static ZEND_EXT_TLS bool zend_opcache_static_cache_entry_locks_process_is_fork_c
379523
#endif
380524
#endif
381525

382-
static zend_always_inline bool zend_opcache_static_cache_force_startup_failure(void)
383-
{
384-
const char *value = getenv("OPCACHE_STATIC_CACHE_FORCE_STARTUP_FAILURE");
385-
386-
return value != NULL && value[0] != '\0' && value[0] != '0';
387-
}
388-
389-
static zend_always_inline bool zend_opcache_static_cache_requires_pre_request_storage(void)
390-
{
391-
return sapi_module.name != NULL && strcmp(sapi_module.name, "fpm-fcgi") == 0;
392-
}
393-
394-
static zend_always_inline void zend_opcache_static_cache_set_unavailable(const char *failure_reason, bool startup_failed)
395-
{
396-
zend_opcache_static_cache_context *context = zend_opcache_static_cache_active_context();
397-
zend_opcache_static_cache_runtime *runtime = zend_opcache_static_cache_context_runtime(context);
398-
399-
runtime->available = false;
400-
runtime->startup_failed = startup_failed;
401-
runtime->backend_initialized = context->storage.initialized;
402-
runtime->failure_reason = failure_reason;
403-
}
404-
405-
static zend_always_inline void zend_opcache_static_cache_set_available(void)
406-
{
407-
zend_opcache_static_cache_context *context = zend_opcache_static_cache_active_context();
408-
zend_opcache_static_cache_runtime *runtime = zend_opcache_static_cache_context_runtime(context);
409-
410-
runtime->available = true;
411-
runtime->startup_failed = false;
412-
runtime->backend_initialized = context->storage.initialized;
413-
runtime->failure_reason = NULL;
414-
}
415-
416-
static zend_always_inline void zend_opcache_static_cache_cleanup_segments(const zend_shared_memory_handlers *handler, zend_shared_segment **segments, int segment_count)
526+
static void zend_opcache_static_cache_cleanup_segments(const zend_shared_memory_handlers *handler, zend_shared_segment **segments, int segment_count)
417527
{
418528
int index;
419529

@@ -869,27 +979,6 @@ static void zend_opcache_static_cache_unlock_impl(void)
869979
}
870980
#endif
871981

872-
static HashTable **zend_opcache_static_cache_entry_locks_ptr_for_context(zend_opcache_static_cache_context *context)
873-
{
874-
return context == &zend_opcache_static_cache_pinned_context_state
875-
? &zend_opcache_static_cache_pinned_entry_locks
876-
: &zend_opcache_static_cache_volatile_entry_locks
877-
;
878-
}
879-
880-
static uint32_t *zend_opcache_static_cache_entry_lock_counts_for_context(zend_opcache_static_cache_context *context)
881-
{
882-
return context == &zend_opcache_static_cache_pinned_context_state
883-
? zend_opcache_static_cache_pinned_entry_lock_counts
884-
: zend_opcache_static_cache_volatile_entry_lock_counts
885-
;
886-
}
887-
888-
static uint32_t zend_opcache_static_cache_entry_lock_stripe(zend_string *key)
889-
{
890-
return (uint32_t) (zend_string_hash_val(key) % ZEND_OPCACHE_STATIC_CACHE_ENTRY_LOCK_STRIPES);
891-
}
892-
893982
#if defined(ZTS) && !defined(ZEND_WIN32)
894983
static void zend_opcache_static_cache_entry_locks_reinit_after_fork(zend_opcache_static_cache_storage *storage)
895984
{
@@ -1395,11 +1484,6 @@ static uint32_t zend_opcache_static_cache_calculate_capacity(size_t size)
13951484
return (uint32_t) capacity;
13961485
}
13971486

1398-
static zend_always_inline uint32_t zend_opcache_static_cache_used_end_offset_locked(const zend_opcache_static_cache_header *header)
1399-
{
1400-
return header->data_offset + header->next_free;
1401-
}
1402-
14031487
static void zend_opcache_static_cache_free_list_remove_locked(zend_opcache_static_cache_header *header, uint32_t block_offset)
14041488
{
14051489
zend_opcache_static_cache_block *block = zend_opcache_static_cache_block_ptr(block_offset);
@@ -1594,29 +1678,6 @@ static bool zend_opcache_static_cache_startup_storage(void)
15941678
return true;
15951679
}
15961680

1597-
static zend_always_inline bool zend_opcache_static_cache_payload_size_to_block_size(size_t size, uint32_t *block_size)
1598-
{
1599-
size_t aligned_size;
1600-
1601-
if (size == 0 || size > UINT32_MAX - sizeof(zend_opcache_static_cache_block)) {
1602-
return false;
1603-
}
1604-
1605-
aligned_size = ZEND_ALIGNED_SIZE(sizeof(zend_opcache_static_cache_block) + size);
1606-
if (aligned_size > UINT32_MAX) {
1607-
return false;
1608-
}
1609-
1610-
*block_size = (uint32_t) aligned_size;
1611-
1612-
return true;
1613-
}
1614-
1615-
static zend_always_inline bool zend_opcache_static_cache_offset_in_block(uint32_t offset, uint32_t block_offset, uint32_t block_size)
1616-
{
1617-
return offset >= block_offset + sizeof(zend_opcache_static_cache_block) && offset < block_offset + block_size;
1618-
}
1619-
16201681
static bool zend_opcache_static_cache_block_is_movable_locked(
16211682
zend_opcache_static_cache_header *header,
16221683
uint32_t block_offset,

0 commit comments

Comments
 (0)