Commit 9eae3ff58ca for php
commit 9eae3ff58ca5152a75f0281f6100b4d3c1a1d866
Author: Alexandre Rulleau <55387832+Leiyks@users.noreply.github.com>
Date: Fri Oct 30 15:35:02 2026 +0100
Load DECLARE_LAMBDA_FUNCTION cache slot once (#24598)
opline->extended_value lives in the (opcache SHM) op_array, so another
process may set it to -1 between the != -1 check and its reuse as a slot
offset, which would then index the run-time cache out of bounds. Read it
once into a local; same for ZEND_CALLABLE_CONVERT.
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index b3d0597374c..c39b82f0160 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -8422,9 +8422,10 @@ ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, UNUSED, NUM, NUM|CACHE_SLOT)
zend_function *func;
zend_object *object;
zend_class_entry *called_scope;
+ uint32_t cache_slot = opline->extended_value;
- if (opline->extended_value != (uint32_t)-1) {
- zend_object *closure = CACHED_PTR(opline->extended_value);
+ if (cache_slot != (uint32_t)-1) {
+ zend_object *closure = CACHED_PTR(cache_slot);
if (closure) {
ZVAL_OBJ_COPY(EX_VAR(opline->result.var), closure);
ZEND_VM_NEXT_OPCODE();
@@ -8447,10 +8448,10 @@ ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, UNUSED, NUM, NUM|CACHE_SLOT)
SAVE_OPLINE();
zend_create_closure(EX_VAR(opline->result.var), func,
EX(func)->op_array.scope, called_scope, object);
- if (opline->extended_value != (uint32_t)-1) {
+ if (cache_slot != (uint32_t)-1) {
zend_object *closure = Z_OBJ_P(EX_VAR(opline->result.var));
GC_ADDREF(closure);
- CACHE_PTR(opline->extended_value, closure);
+ CACHE_PTR(cache_slot, closure);
zend_stack_push(&EG(lambda_cache), &closure);
}
ZEND_VM_NEXT_OPCODE();
@@ -9852,9 +9853,10 @@ ZEND_VM_HANDLER(202, ZEND_CALLABLE_CONVERT, UNUSED, UNUSED, NUM|CACHE_SLOT)
{
USE_OPLINE
zend_execute_data *call = EX(call);
+ uint32_t cache_slot = opline->extended_value;
- if (opline->extended_value != (uint32_t)-1) {
- zend_object *closure = CACHED_PTR(opline->extended_value);
+ if (cache_slot != (uint32_t)-1) {
+ zend_object *closure = CACHED_PTR(cache_slot);
if (closure) {
ZVAL_OBJ_COPY(EX_VAR(opline->result.var), closure);
} else {
@@ -9869,7 +9871,7 @@ ZEND_VM_HANDLER(202, ZEND_CALLABLE_CONVERT, UNUSED, UNUSED, NUM|CACHE_SLOT)
ZEND_ASSERT(Z_TYPE_P(closure_zv) == IS_OBJECT);
closure = Z_OBJ_P(closure_zv);
ZVAL_OBJ_COPY(EX_VAR(opline->result.var), closure);
- CACHE_PTR(opline->extended_value, closure);
+ CACHE_PTR(cache_slot, closure);
}
} else {
zend_closure_from_frame(EX_VAR(opline->result.var), call);
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 74ed4301047..89fefc884b0 100644
Binary files a/Zend/zend_vm_execute.h and b/Zend/zend_vm_execute.h differ