Skip to content

Segfault with hook "simple get" cache slot and minimal JIT #15834

Closed
@nielsdos

Description

@nielsdos

Description

Originally posted in #15819 (comment)

The following code:

<?php
class A {
    private $_prop;
    public $prop {
        get => $this->_prop;
    }
}
for ($i=0;$i<2;$i++)
    echo (new A)->prop;

using opcache.jit=1101

Resulted in this output:

Segfault

But I expected this output instead:

No segfault

I analysed this and this is a different bug related to a cache slot optimization.
As far as I understand, this happens for when the cache slot satisfies the ZEND_IS_PROPERTY_HOOK_SIMPLE_GET condition. Then we set up a function call frame and re-enter the VM to execute the hook function:

php-src/Zend/zend_vm_def.h

Lines 2094 to 2126 in 7c2204c

} else if (EXPECTED(ZEND_IS_PROPERTY_HOOK_SIMPLE_GET(prop_offset))) {
zend_function *hook = prop_info->hooks[ZEND_PROPERTY_HOOK_GET];
ZEND_ASSERT(hook->type == ZEND_USER_FUNCTION);
ZEND_ASSERT(RUN_TIME_CACHE(&hook->op_array));
uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS;
if (OP1_TYPE & IS_CV) {
GC_ADDREF(zobj);
}
if (OP1_TYPE & (IS_CV|IS_VAR|IS_TMP_VAR)) {
call_info |= ZEND_CALL_RELEASE_THIS;
}
zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj);
call->prev_execute_data = execute_data;
call->call = NULL;
call->return_value = EX_VAR(opline->result.var);
call->run_time_cache = RUN_TIME_CACHE(&hook->op_array);
execute_data = call;
EG(current_execute_data) = execute_data;
zend_init_cvs(0, hook->op_array.last_var EXECUTE_DATA_CC);
#if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
opline = hook->op_array.opcodes;
#else
EX(opline) = hook->op_array.opcodes;
#endif
LOAD_OPLINE_EX();
ZEND_OBSERVER_SAVE_OPLINE();
ZEND_OBSERVER_FCALL_BEGIN(execute_data);
ZEND_VM_ENTER_EX();
}

This seems incompatible with how the minimal JIT works, getting the property will be skipped.
Indeed if we get rid of ZEND_SET_PROPERTY_HOOK_SIMPLE_GET in zend_object_handlers.c or go to a higher optimization level the problem disappears. I'm not sure yet how to solve that.

PHP Version

master

Operating System

Linux

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions