Skip to content

Add internal API for Error Notification Callbacks #4555

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 1 commit into from

Conversation

beberlei
Copy link
Contributor

@beberlei beberlei commented Aug 18, 2019

PHP Extensions are able to hook into the error mechanism of the Zend Engine by overwriting the zend_error_cb callback. This callback has a lot of responsibilities though (display, repeated error supression, logging, exception conversion), so that overwriting is quite difficult. A few extensions also overwrite the error handler in a way that previous handlers are not called anymore (xdebug), making it unreliable.

This PR introduces a new API that allows extensions to register global error notification handlers.

  • These handlers are only responsible for processing errors and notifying third party systems with a guarantee that they are called. Stopping propagation is explicitly not the idea of this API. Handlers are supposed to have no side effects on further error processing.
  • These handlers are implemented as zend_llist, so no care has to be taken to call previous handlers, making it more robust than chaining function pointers.
  • The notification callbacks are triggered outside of php_error_cb, so that it is guaranteed they are always called when an error occurs, even when zend_error_cb is overwritten. This also means that the notification happens before repeatable errors are ignored and last_error is updated.
  • This API is internal and not exposed to userland.

Example

As an example I was able to refactor the inlined DTrace notification handling into the new API.

report_zend_debug code is also be a candidate for being a notification callback and was migrated. This debug code is not used anywhere, maybe it should be removed though?

Usage Example:

void dtrace_error_notify_cb(int type, const char *error_filename, uint32_t error_lineno, zend_string *message)
{
	if (DTRACE_ERROR_ENABLED()) {
		DTRACE_ERROR(ZSTR_VAL(message), (char *)error_filename, error_lineno);
	}
}

zend_register_error_notify_callback(dtrace_error_notify_cb);

Questions

  • Should this be part of the proposed new zend_instrument API? zend_instrument_install_error_callback(cb)

Out of scope

The error mechanism can use a larger cleanup as discussed in the Improved Error Callbacks Mechanism RFC that was never implemented.

This PR is only about a reliable notification callback for now. Other changes may follow this.

@beberlei beberlei force-pushed the ErrorNotifications branch 2 times, most recently from 88d0486 to 28b1529 Compare April 27, 2020 06:21
@beberlei beberlei marked this pull request as ready for review April 27, 2020 06:21
@nikic
Copy link
Member

nikic commented May 29, 2020

One thing to note here is that there's some places that directly call zend_error_cb.

@nikic
Copy link
Member

nikic commented Jun 5, 2020

Needs a rebase after #5639.

@beberlei beberlei force-pushed the ErrorNotifications branch from 28b1529 to ccffa02 Compare June 5, 2020 08:46
Copy link
Member

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks reasonable to me.

Zend/zend.h Outdated
@@ -351,6 +351,22 @@ ZEND_API void zend_save_error_handling(zend_error_handling *current);
ZEND_API void zend_replace_error_handling(zend_error_handling_t error_handling, zend_class_entry *exception_class, zend_error_handling *current);
ZEND_API void zend_restore_error_handling(zend_error_handling *saved);

typedef void (*zend_error_notify_cb)(int type, const char *error_filename, const uint32_t error_lineno, zend_string *message);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere, do not use const uint32_t, just uint32_t. This makes particularly little sense inside signatures.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zend_error_cb also has const uint32_t in signature, thats where I copied it from. Probably good to have another PR to clean that up, because it affects at least ext/soap

@morrisonlevi
Copy link
Contributor

morrisonlevi commented Jun 5, 2020

I'm a bit busy so I went through it quickly. Checking one thing:

This also means that the notification happens before repeatable errors are ignored and last_error is updated.

Can you give me an example? I have avoided the previous hooks because I was aware of the unreliability, so I'm not familiar this case.

@beberlei
Copy link
Contributor Author

beberlei commented Jun 5, 2020

@morrisonlevi In php_error_cb there is code that checks the ini setting ignore_repeated_errors. If that is On, then the log_errors + display_errors code is not executed, when the previous error (based on the full message!) is exactly the same. This is mostly important for warnings, notices and deprecations.

@beberlei
Copy link
Contributor Author

@krakjoe @nikic @Girgias @morrisonlevi i am going to merge this next week unless you have comments.

@beberlei beberlei force-pushed the ErrorNotifications branch from 7eb1b74 to 87df1a7 Compare July 14, 2020 07:33
@beberlei
Copy link
Contributor Author

merged with 6c8b94e

@beberlei beberlei closed this Jul 17, 2020

BEGIN_EXTERN_C()

void zend_register_error_notify_callback(zend_error_notify_cb callback);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be ZEND_API?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it should.

Copy link
Contributor Author

@beberlei beberlei Jul 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, will fix it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah you already committed this yesterday, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants