-
Notifications
You must be signed in to change notification settings - Fork 63
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
fix(agent): Additional checks needed before iterating backwards in opcodes. #639
Conversation
Since our logic depends on what we know about ZEND_DO_FCALL, verify this is actually a ZEND_DO_FCALL otherwise exit.
ok jenkins |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zsistla I would appreciate if you could you add some context to the description of this PR. I.e. what code path caused the execute_data
to be NULL and under which circumstances this function was called when ZEND_DO_FCALL != execute_data->prev_execute_data->opline->opcode
? This would be most helpful to understand the need for these changes.
Please see updated description. |
ok jenkins |
3 similar comments
ok jenkins |
ok jenkins |
ok jenkins |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (ZEND_DO_FCALL != execute_data->prev_execute_data->opline->opcode) {
return;
}
is the key in this PR and addresses the segfault, caused by OAPI's instrumentation of user functions called via call_user_function_array
which assumes that DO_FCALL
is the opcode of the previous call frame. This needs to be ensured and that extra check does it. Nice find!
Added a message when execute_data is NULL and removed the check for execute_data->opline as we don't use that value.
Here's a suggestion I have that will improve code review experience: apply a coding style with clang-format only to new code added to an existing code base. This will reduce 'background noise' and help reviewers keep focused on the new/changed code. Here's how this can be added to the code/commit workflow:
This could be semi-automated with git hook: https://github.com/barisione/clang-format-hooks/#using-the-pre-commit-hook. |
Obsolete. Superseded by #708. |
nr_php_observer_attempt_call_cufa_handler
is a new function with oapi. The equivalent function for non-oapi is in php_vm.c. In that case, it has been called while we are in the middle of php_execute and can assume certain things among them being we can just check the execute_data opcodes and that the start opcode is ZEND_DO_FCALL (of which we know certain facts) and iterate back as needed.In legacy, to determine determine this is a call_user_func_array() call we have to look at the previous opcodes of zend_execute_data.
In oapi, to determine if this is a call_user_func_array() call we have to look at the previous opcodes of zend_execute_data->prev_execute_data.
For both we know:
ZEND_DO_FCALL will never be the first opcode in an op array -- minimally, there is always at least a ZEND_INIT_FCALL before it -- so it is safe to iterate backwards in the opcode like
execute_data->prev_execute_data->opline - 1
In oapi, the path to the equivalent function didn't have a guaranteed existence of zend_execute_data and therefore was causing some segfaults (specifically noticed for PHP 8.2 on wordpress which makes extensive use of cufa for hook implementation). Additionally, we are not guaranteed that the prev_execute_data opcode is ZEND_DO_FCALL so we can't blindly iterate backwards on it.
This PR does two things:
Testing:
Build from source soak tests for PHP 8.2 and wordpress no longer segfault.