Skip to content

Commit 2542357

Browse files
committed
Fix GH-17866: zend_mm_heap corrupted error after upgrading from 8.4.3 to 8.4.4
This regressed in GH-17592. The function is with its attributes HashTable* is copied in zend_get_closure_invoke_method() but its refcount is not increased. This caused a crash in the Symfony demo page. Closes GH-17880.
1 parent c0857e0 commit 2542357

File tree

5 files changed

+40
-11
lines changed

5 files changed

+40
-11
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ PHP NEWS
1919
may call hooks of overridden properties). (Arnaud)
2020
. Fixed bug GH-17916 (Final abstract properties should error).
2121
(DanielEScherzer)
22+
. Fixed bug GH-17866 (zend_mm_heap corrupted error after upgrading from
23+
8.4.3 to 8.4.4). (nielsdos)
2224

2325
- DOM:
2426
. Fixed bug GH-17609 (Typo in error message: Dom\NO_DEFAULT_NS instead of
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
GH-17866 (zend_mm_heap corrupted error after upgrading from 8.4.3 to 8.4.4)
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
#[Deprecated("xyzzy")]
8+
public function __invoke() {
9+
echo "In __invoke\n";
10+
}
11+
}
12+
13+
$foo = new Foo;
14+
$closure = Closure::fromCallable($foo);
15+
$test = $closure->__invoke(...);
16+
17+
$rc = new ReflectionMethod($test, '__invoke');
18+
var_dump($rc->getAttributes());
19+
var_dump($rc->isDeprecated());
20+
21+
$test();
22+
23+
?>
24+
--EXPECTF--
25+
array(1) {
26+
[0]=>
27+
object(ReflectionAttribute)#%d (1) {
28+
["name"]=>
29+
string(10) "Deprecated"
30+
}
31+
}
32+
bool(true)
33+
34+
Deprecated: Method Foo::__invoke() is deprecated, xyzzy in %s on line %d
35+
In __invoke

Zend/zend_closures.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *object) /* {
464464
zend_closure *closure = (zend_closure *)object;
465465
zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));
466466
const uint32_t keep_flags =
467-
ZEND_ACC_RETURN_REFERENCE | ZEND_ACC_VARIADIC | ZEND_ACC_HAS_RETURN_TYPE;
467+
ZEND_ACC_RETURN_REFERENCE | ZEND_ACC_VARIADIC | ZEND_ACC_HAS_RETURN_TYPE | ZEND_ACC_DEPRECATED;
468468

469469
invoke->common = closure->func.common;
470470
/* We return ZEND_INTERNAL_FUNCTION, but arg_info representation is the

Zend/zend_object_handlers.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,12 +1618,8 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce
16181618
| ZEND_ACC_PUBLIC
16191619
| ZEND_ACC_VARIADIC
16201620
| (fbc->common.fn_flags & (ZEND_ACC_RETURN_REFERENCE|ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED));
1621-
if (fbc->common.attributes) {
1622-
func->attributes = fbc->common.attributes;
1623-
GC_TRY_ADDREF(func->attributes);
1624-
} else {
1625-
func->attributes = NULL;
1626-
}
1621+
/* Attributes outlive the trampoline because they are created by the compiler. */
1622+
func->attributes = fbc->common.attributes;
16271623
if (is_static) {
16281624
func->fn_flags |= ZEND_ACC_STATIC;
16291625
}

Zend/zend_object_handlers.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,10 +339,6 @@ ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_p
339339
} while (0)
340340

341341
#define zend_free_trampoline(func) do { \
342-
HashTable *attributes = (func)->common.attributes; \
343-
if (attributes && !(GC_FLAGS(attributes) & GC_IMMUTABLE) && !GC_DELREF(attributes)) { \
344-
zend_array_destroy(attributes); \
345-
} \
346342
if ((func) == &EG(trampoline)) { \
347343
EG(trampoline).common.attributes = NULL; \
348344
EG(trampoline).common.function_name = NULL; \

0 commit comments

Comments
 (0)