Skip to content

JIT has wrong expectations for ZEND_FETCH_OBJ_FUNC_ARG when the prop is hooked #21006

@arnaud-lb

Description

@arnaud-lb

Description

The following code:

namespace Test;

class C
{
    public $prop {
        get => 'sha256';
    }

    public function sign()
    {
        return hash_hmac(
            algo: $this->prop,
            data: '',
            key: '',
        );
    }
}

$obj = new C();
for ($i = 0; $i < 2; $i++) {
    $obj->sign('test');
}

When executed with

php -n -d opcache.enable_cli=1 -d opcache.jit=tracing -d opcache.jit_hot_loop=1 test.php

Results in

Program received signal SIGSEGV, Segmentation fault.
0x0000000000d3ea39 in zend_handle_named_arg (call_ptr=0x7ffff3e18168, arg_name=0xac002e000, arg_num_ptr=0x7fffffffaf84, cache_slot=0x8000f3e0779f) at Zend/zend_execute.c:5515
5515		zend_function *fbc = call->func;
(gdb) bt
#0  0x0000000000d3ea39 in zend_handle_named_arg (call_ptr=0x7ffff3e18168, arg_name=0xac002e000, arg_num_ptr=0x7fffffffaf84, cache_slot=0x8000f3e0779f) at Zend/zend_execute.c:5515
#1  0x0000000000d7cbb9 in ZEND_SEND_FUNC_ARG_SPEC_VAR_CONST_HANDLER () at Zend/zend_vm_execute.h:26393
#2  0x000000000ac00b3f in TRACE-1$test.php$22 () at unknown:1
#3  0x0000000000dbfec9 in zend_execute (op_array=0x0, return_value=0x7ffff3e761c0) at Zend/zend_vm_execute.h:121866

The cause seems to be that ZEND_FETCH_OBJ_FUNC_ARG may push a new call frame (when the hook is marked as SIMPLE_GET), but zend_jit_trace_handler() doesn't expect that, so the JIT trace continues execution with the wrong call frame.

In the reproducer, we call ZEND_FETCH_OBJ_FUNC_ARG for $this->prop from TRACE-1$test.php$22, which pushes a stack frame for a call to Test\C::$prop::get, and returns. The trace calls ZEND_SEND_FUNC_ARG for algo: $this->prop, and crashes when accessing EX(call)->func because EX(call) is null.

The crash was discovered by @TimWolla.

PHP Version

PHP 8.5

Operating System

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions