-
Notifications
You must be signed in to change notification settings - Fork 7.9k
[Observer] Provide unused retvals to observers #6422
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
Changes from 8 commits
226d9f3
69061b9
836ef0b
d29998d
9332095
95f943a
0fa78a5
51d8fd9
7b6572f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4248,7 +4248,11 @@ ZEND_VM_INLINE_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY, SPEC(OBSERVER)) | |
if (return_value) { | ||
ZVAL_NULL(return_value); | ||
} | ||
ZEND_OBSERVER_SAVE_OPLINE(); | ||
ZEND_OBSERVER_FCALL_END(execute_data, retval_ptr); | ||
} else if (!return_value) { | ||
ZEND_OBSERVER_SAVE_OPLINE(); | ||
ZEND_OBSERVER_FCALL_END(execute_data, retval_ptr); | ||
if (OP1_TYPE & (IS_VAR|IS_TMP_VAR)) { | ||
if (Z_REFCOUNTED_P(retval_ptr) && !Z_DELREF_P(retval_ptr)) { | ||
SAVE_OPLINE(); | ||
|
@@ -4263,6 +4267,8 @@ ZEND_VM_INLINE_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY, SPEC(OBSERVER)) | |
Z_ADDREF_P(return_value); | ||
} | ||
} | ||
ZEND_OBSERVER_SAVE_OPLINE(); | ||
ZEND_OBSERVER_FCALL_END(execute_data, retval_ptr); | ||
} else if (OP1_TYPE == IS_CV) { | ||
do { | ||
if (Z_OPT_REFCOUNTED_P(retval_ptr)) { | ||
|
@@ -4274,6 +4280,8 @@ ZEND_VM_INLINE_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY, SPEC(OBSERVER)) | |
gc_possible_root(ref); | ||
} | ||
ZVAL_NULL(retval_ptr); | ||
ZEND_OBSERVER_SAVE_OPLINE(); | ||
ZEND_OBSERVER_FCALL_END(execute_data, return_value); | ||
break; | ||
} else { | ||
Z_ADDREF_P(retval_ptr); | ||
|
@@ -4286,6 +4294,8 @@ ZEND_VM_INLINE_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY, SPEC(OBSERVER)) | |
} | ||
} | ||
ZVAL_COPY_VALUE(return_value, retval_ptr); | ||
ZEND_OBSERVER_SAVE_OPLINE(); | ||
ZEND_OBSERVER_FCALL_END(execute_data, retval_ptr); | ||
} while (0); | ||
} else /* if (OP1_TYPE == IS_VAR) */ { | ||
if (UNEXPECTED(Z_ISREF_P(retval_ptr))) { | ||
|
@@ -4301,10 +4311,10 @@ ZEND_VM_INLINE_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY, SPEC(OBSERVER)) | |
} else { | ||
ZVAL_COPY_VALUE(return_value, retval_ptr); | ||
} | ||
ZEND_OBSERVER_SAVE_OPLINE(); | ||
ZEND_OBSERVER_FCALL_END(execute_data, retval_ptr); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there's still a potential use-after-free here. If retval_ptr is a reference with refcount one, then it will be freed above, but (the new) retval_ptr will still point into it. Generally I think that you should just do
one at the end up the whole |
||
} | ||
} | ||
ZEND_OBSERVER_SAVE_OPLINE(); | ||
ZEND_OBSERVER_FCALL_END(execute_data, return_value); | ||
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); | ||
} | ||
|
||
|
@@ -4323,17 +4333,20 @@ ZEND_VM_COLD_CONST_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY, SRC, | |
|
||
retval_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R); | ||
if (!EX(return_value)) { | ||
ZEND_OBSERVER_FCALL_END(execute_data, retval_ptr); | ||
FREE_OP1(); | ||
} else { | ||
if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_ISREF_P(retval_ptr))) { | ||
ZVAL_COPY_VALUE(EX(return_value), retval_ptr); | ||
ZEND_OBSERVER_FCALL_END(execute_data, retval_ptr); | ||
break; | ||
} | ||
|
||
ZVAL_NEW_REF(EX(return_value), retval_ptr); | ||
if (OP1_TYPE == IS_CONST) { | ||
Z_TRY_ADDREF_P(retval_ptr); | ||
} | ||
ZEND_OBSERVER_FCALL_END(execute_data, retval_ptr); | ||
} | ||
break; | ||
} | ||
|
@@ -4346,7 +4359,9 @@ ZEND_VM_COLD_CONST_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY, SRC, | |
zend_error(E_NOTICE, "Only variable references should be returned by reference"); | ||
if (EX(return_value)) { | ||
ZVAL_NEW_REF(EX(return_value), retval_ptr); | ||
ZEND_OBSERVER_FCALL_END(execute_data, retval_ptr); | ||
} else { | ||
ZEND_OBSERVER_FCALL_END(execute_data, retval_ptr); | ||
FREE_OP1_VAR_PTR(); | ||
} | ||
break; | ||
|
@@ -4362,10 +4377,10 @@ ZEND_VM_COLD_CONST_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY, SRC, | |
ZVAL_REF(EX(return_value), Z_REF_P(retval_ptr)); | ||
} | ||
|
||
ZEND_OBSERVER_FCALL_END(execute_data, retval_ptr); | ||
FREE_OP1_VAR_PTR(); | ||
} while (0); | ||
|
||
ZEND_OBSERVER_FCALL_END(execute_data, EX(return_value)); | ||
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); | ||
} | ||
|
||
|
@@ -7710,7 +7725,7 @@ ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_ca | |
|
||
/* Uncaught exception */ | ||
if (zend_observer_fcall_op_array_extension != -1) { | ||
zend_observer_fcall_end(execute_data, EX(return_value)); | ||
zend_observer_fcall_end(execute_data, NULL); | ||
} | ||
cleanup_live_vars(execute_data, op_num, 0); | ||
if (UNEXPECTED((EX_CALL_INFO() & ZEND_CALL_GENERATOR) != 0)) { | ||
|
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.
Might it make sense to just move this to the very start of the function, rather than duplication it in the branches?
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.
That would make sense and would be simpler. But the main issue is that any errors that are raised in the return handler would trigger after the end handler had fired.
For example, the output from
observer_retval_05.phpt
would change to this:For the PHP tracer extension I'm working on, that would mean that we couldn't attach the
E_WARNING
to the openfoo
span that raised the error.