Skip to content

Commit bccda7e

Browse files
committed
Extended map_ptr before copying class table (#9188)
Fixes GH-9164
1 parent 7ff71a0 commit bccda7e

File tree

3 files changed

+58
-11
lines changed

3 files changed

+58
-11
lines changed

Zend/zend_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) {
724724

725725
#define ZSTR_SET_CE_CACHE_EX(s, ce, validate) do { \
726726
if (!(validate) || ZSTR_VALID_CE_CACHE(s)) { \
727+
ZEND_ASSERT((validate) || ZSTR_VALID_CE_CACHE(s)); \
727728
SET_CE_CACHE(GC_REFCOUNT(s), ce); \
728729
} \
729730
} while (0)

ext/opcache/tests/gh9164.phpt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--TEST--
2+
Bug GH-9164: Segfault in zend_accel_class_hash_copy
3+
--EXTENSIONS--
4+
opcache
5+
pcntl
6+
--INI--
7+
opcache.enable_cli=1
8+
--FILE--
9+
<?php
10+
11+
$incfile = __DIR__.'/gh9164.inc';
12+
13+
// Generate enough classes so that the out of bound access will cause a crash
14+
// without relying on assertion
15+
$fd = fopen($incfile, 'w');
16+
fwrite($fd, "<?php\n");
17+
for ($i = 0; $i < 4096; $i++) {
18+
fprintf($fd, "class FooBar%04d {}\n", $i);
19+
}
20+
fclose($fd);
21+
22+
// Ensure cacheability
23+
touch($incfile, time() - 3600);
24+
25+
$pid = pcntl_fork();
26+
if ($pid == 0) {
27+
// Child: Declare classes to allocate CE cache slots.
28+
require $incfile;
29+
} else if ($pid > 0) {
30+
pcntl_wait($status);
31+
// Ensure that file has been cached. If not, this is testing nothing anymore.
32+
if (!isset(opcache_get_status()['scripts'][$incfile])) {
33+
print "File not cached\n";
34+
}
35+
// Populates local cache
36+
require $incfile;
37+
var_dump(new FooBar4095);
38+
unlink($incfile);
39+
} else {
40+
echo "pcntl_fork() failed\n";
41+
}
42+
43+
?>
44+
--EXPECTF--
45+
object(FooBar4095)#%d (0) {
46+
}

ext/opcache/zend_accelerator_util_funcs.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -222,15 +222,11 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script,
222222
op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
223223
*op_array = persistent_script->script.main_op_array;
224224

225-
if (zend_hash_num_elements(&persistent_script->script.function_table) > 0) {
226-
zend_accel_function_hash_copy(CG(function_table), &persistent_script->script.function_table);
227-
}
228-
229-
if (zend_hash_num_elements(&persistent_script->script.class_table) > 0) {
230-
zend_accel_class_hash_copy(CG(class_table), &persistent_script->script.class_table);
231-
}
232-
233225
if (EXPECTED(from_shared_memory)) {
226+
if (ZCSG(map_ptr_last) > CG(map_ptr_last)) {
227+
zend_map_ptr_extend(ZCSG(map_ptr_last));
228+
}
229+
234230
/* Register __COMPILER_HALT_OFFSET__ constant */
235231
if (persistent_script->compiler_halt_offset != 0 &&
236232
persistent_script->script.filename) {
@@ -243,10 +239,14 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script,
243239
}
244240
zend_string_release_ex(name, 0);
245241
}
242+
}
246243

247-
if (ZCSG(map_ptr_last) > CG(map_ptr_last)) {
248-
zend_map_ptr_extend(ZCSG(map_ptr_last));
249-
}
244+
if (zend_hash_num_elements(&persistent_script->script.function_table) > 0) {
245+
zend_accel_function_hash_copy(CG(function_table), &persistent_script->script.function_table);
246+
}
247+
248+
if (zend_hash_num_elements(&persistent_script->script.class_table) > 0) {
249+
zend_accel_class_hash_copy(CG(class_table), &persistent_script->script.class_table);
250250
}
251251

252252
if (persistent_script->script.first_early_binding_opline != (uint32_t)-1) {

0 commit comments

Comments
 (0)