Skip to content

Ignore ZEND_EXIT, ZEND_BEGIN_SILENCE, ZEND_END_SILENCE in JIT check #6640

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Zend/zend_vm_opcodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,3 +442,13 @@ ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode) {
}
return zend_vm_opcodes_flags[opcode];
}
ZEND_API zend_uchar zend_get_opcode_id(const char *name, size_t length) {
zend_uchar opcode;
for (opcode = 0; opcode < (sizeof(zend_vm_opcodes_names) / sizeof(zend_vm_opcodes_names[0])) - 1; opcode++) {
if (strncmp(zend_vm_opcodes_names[opcode], name, length) == 0) {
return opcode;
}
}
return ZEND_VM_LAST_OPCODE + 1;
}

1 change: 1 addition & 0 deletions Zend/zend_vm_opcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ BEGIN_EXTERN_C()

ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(zend_uchar opcode);
ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode);
ZEND_API zend_uchar zend_get_opcode_id(const char *name, size_t length);

END_EXTERN_C()

Expand Down
18 changes: 13 additions & 5 deletions ext/opcache/jit/zend_jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -4234,11 +4234,19 @@ ZEND_EXT_API int zend_jit_check_support(void)
}

for (i = 0; i <= 256; i++) {
if (zend_get_user_opcode_handler(i) != NULL) {
zend_error(E_WARNING, "JIT is incompatible with third party extensions that setup user opcode handlers. JIT disabled.");
JIT_G(enabled) = 0;
JIT_G(on) = 0;
return FAILURE;
switch (i) {
/* JIT has no effect on these opcodes */
case ZEND_BEGIN_SILENCE:
case ZEND_END_SILENCE:
case ZEND_EXIT:
break;
default:
if (zend_get_user_opcode_handler(i) != NULL) {
zend_error(E_WARNING, "JIT is incompatible with third party extensions that setup user opcode handlers. JIT disabled.");
JIT_G(enabled) = 0;
JIT_G(on) = 0;
return FAILURE;
}
}
}

Expand Down
32 changes: 32 additions & 0 deletions ext/opcache/tests/jit/ignored_opcodes.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
JIT: ignored opcodes
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit_buffer_size=1M
opcache.jit=function
;opcache.jit_debug=257
zend_test.observer.enabled=1
zend_test.observer.observe_all=1
zend_test.observer.show_opcode_in_user_handler=ZEND_EXIT, ZEND_BEGIN_SILENCE, ZEND_END_SILENCE
--SKIPIF--
<?php require_once('skipif.inc'); ?>
<?php if (!extension_loaded('zend_test')) die('skip: zend_test extension required'); ?>
--FILE--
<?php
function test(): int
{
return 0;
}

exit(@test());
?>
--EXPECTF--
<!-- init '%s' -->
<file '%s'>
<!-- opcode: 'ZEND_BEGIN_SILENCE' in user handler -->
<!-- opcode: 'ZEND_END_SILENCE' in user handler -->
<!-- opcode: 'ZEND_EXIT' in user handler -->
<!-- Exception: UnwindExit -->
</file '%s'>
42 changes: 42 additions & 0 deletions ext/zend_test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
int observer_show_return_value;
int observer_show_init_backtrace;
int observer_show_opcode;
char *observer_show_opcode_in_user_handler;
int observer_nesting_depth;
int replace_zend_execute_ex;
ZEND_END_MODULE_GLOBALS(zend_test)
Expand Down Expand Up @@ -346,6 +347,7 @@ PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_value", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_value, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_BOOLEAN("zend_test.observer.show_init_backtrace", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_init_backtrace, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_BOOLEAN("zend_test.observer.show_opcode", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_opcode, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_ENTRY("zend_test.observer.show_opcode_in_user_handler", "", PHP_INI_SYSTEM, OnUpdateString, observer_show_opcode_in_user_handler, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals)
PHP_INI_END()

Expand All @@ -357,6 +359,42 @@ static void custom_zend_execute_ex(zend_execute_data *execute_data)
old_zend_execute_ex(execute_data);
}

static int observer_show_opcode_in_user_handler(zend_execute_data *execute_data)
{
if (ZT_G(observer_show_output)) {
php_printf("%*s<!-- opcode: '%s' in user handler -->\n", 2 * ZT_G(observer_nesting_depth), "", zend_get_opcode_name(EX(opline)->opcode));
}

return ZEND_USER_OPCODE_DISPATCH;
}

static void observer_set_user_opcode_handler(const char *opcode_names, user_opcode_handler_t handler)
{
const char *s = NULL, *e = opcode_names;

while (1) {
if (*e == ' ' || *e == ',' || *e == '\0') {
if (s) {
zend_uchar opcode = zend_get_opcode_id(s, e - s);
if (opcode <= ZEND_VM_LAST_OPCODE) {
zend_set_user_opcode_handler(opcode, handler);
} else {
zend_error(E_WARNING, "Invalid opcode name %.*s", (int) (e - s), e);
}
s = NULL;
}
} else {
if (!s) {
s = e;
}
}
if (*e == '\0') {
break;
}
e++;
}
}

PHP_MINIT_FUNCTION(zend_test)
{
zend_test_interface = register_class__ZendTestInterface();
Expand Down Expand Up @@ -400,6 +438,10 @@ PHP_MINIT_FUNCTION(zend_test)
zend_execute_ex = custom_zend_execute_ex;
}

if (ZT_G(observer_enabled) && ZT_G(observer_show_opcode_in_user_handler)) {
observer_set_user_opcode_handler(ZT_G(observer_show_opcode_in_user_handler), observer_show_opcode_in_user_handler);
}

return SUCCESS;
}

Expand Down