Skip to content

Commit c209e0d

Browse files
committed
Fix GH-13712: Segmentation fault for enabled observers when calling trait method of internal trait when opcache is loaded
Inherited methods regardless of source must share the original runtime cache. Traits were missed. This adds ZEND_ACC_TRAIT_CLONE to internal functions as well to allow easy distinction of these. On top of that, also fixing the minimum base of the shared opcache memory to 0x4000 to avoid a possible 0x0 base, which may cause all sorts of segfaults. (Breaks WSL 1.)
1 parent afdabb1 commit c209e0d

File tree

5 files changed

+28
-3
lines changed

5 files changed

+28
-3
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ PHP NEWS
2020
- Opcache:
2121
. Fixed GH-13508 (JITed QM_ASSIGN may be optimized out when op1 is null).
2222
(Arnaud, Dmitry)
23+
. Fixed GH-13712 (Segmentation fault for enabled observers when calling trait
24+
method of internal trait when opcache is loaded). (Bob)
2325

2426
- PDO:
2527
. Fix various PDORow bugs. (Girgias)

Zend/zend_inheritance.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1917,9 +1917,9 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
19171917
} else {
19181918
new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
19191919
memcpy(new_fn, fn, sizeof(zend_op_array));
1920-
new_fn->op_array.fn_flags |= ZEND_ACC_TRAIT_CLONE;
19211920
new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
19221921
}
1922+
new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
19231923

19241924
/* Reassign method name, in case it is an alias. */
19251925
new_fn->common.function_name = name;

ext/opcache/shared_alloc_mmap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
static void *find_prefered_mmap_base(size_t requested_size)
5050
{
5151
size_t huge_page_size = 2 * 1024 * 1024;
52-
uintptr_t last_free_addr = 0;
52+
uintptr_t last_free_addr = 0x4000;
5353
uintptr_t last_candidate = (uintptr_t)MAP_FAILED;
5454
uintptr_t start, end, text_start = 0;
5555
#if defined(__linux__)

ext/opcache/tests/gh13712.phpt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
GH-13712 (Segmentation fault for enabled observers when calling trait method of internal trait when opcache is loaded)
3+
--EXTENSIONS--
4+
opcache
5+
zend_test
6+
--INI--
7+
zend_test.observer.enabled=1
8+
opcache.enable=1
9+
opcache.enable_cli=1
10+
--FILE--
11+
<?php
12+
class Foo {
13+
use _ZendTestTrait;
14+
}
15+
16+
$f = new Foo();
17+
var_dump($f->testMethod());
18+
?>
19+
--EXPECTF--
20+
<!-- init '%s' -->
21+
<!-- init Foo::testMethod() -->
22+
<!-- init var_dump() -->
23+
bool(true)

ext/opcache/zend_persist.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ static void zend_persist_class_method(zval *zv, zend_class_entry *ce)
726726
}
727727
// Real dynamically created internal functions like enum methods must have their own run_time_cache pointer. They're always on the same scope as their defining class.
728728
// However, copies - as caused by inheritance of internal methods - must retain the original run_time_cache pointer, shared with the source function.
729-
if (!op_array->scope || op_array->scope == ce) {
729+
if (!op_array->scope || (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE))) {
730730
ZEND_MAP_PTR_NEW(op_array->run_time_cache);
731731
}
732732
}

0 commit comments

Comments
 (0)