-
Notifications
You must be signed in to change notification settings - Fork 8k
Zend: Preallocate error buffer with capacity tracking #20565
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 3 commits
cef4d30
155e86f
49c8d34
cbddab7
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 |
|---|---|---|
|
|
@@ -643,6 +643,7 @@ static FILE *zend_fopen_wrapper(zend_string *filename, zend_string **opened_path | |
| } | ||
| /* }}} */ | ||
|
|
||
|
|
||
| #ifdef ZTS | ||
| static bool short_tags_default = true; | ||
| static uint32_t compiler_options_default = ZEND_COMPILE_DEFAULT; | ||
|
|
@@ -833,8 +834,7 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{ | |
| #endif | ||
| executor_globals->flags = EG_FLAGS_INITIAL; | ||
| executor_globals->record_errors = false; | ||
| executor_globals->num_errors = 0; | ||
| executor_globals->errors = NULL; | ||
| memset(&executor_globals->errors, 0, sizeof(executor_globals->errors)); | ||
| executor_globals->filename_override = NULL; | ||
| executor_globals->lineno_override = -1; | ||
| #ifdef ZEND_CHECK_STACK_LIMIT | ||
|
|
@@ -1446,8 +1446,9 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( | |
| zend_stack delayed_oplines_stack; | ||
| int type = orig_type & E_ALL; | ||
| bool orig_record_errors; | ||
| uint32_t orig_num_errors; | ||
| zend_error_info **orig_errors; | ||
| uint32_t orig_num_errors = 0; | ||
| uint32_t orig_cap_errors = 0; | ||
| zend_error_info **orig_errors = NULL; | ||
|
Member
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. Here it maybe possible to replace these 3 variables by a single |
||
| zend_result res; | ||
|
|
||
| /* If we're executing a function during SCCP, count any warnings that may be emitted, | ||
|
|
@@ -1459,11 +1460,11 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( | |
| } | ||
|
|
||
| /* Emit any delayed error before handling fatal error */ | ||
| if ((type & E_FATAL_ERRORS) && !(type & E_DONT_BAIL) && EG(num_errors)) { | ||
| uint32_t num_errors = EG(num_errors); | ||
| zend_error_info **errors = EG(errors); | ||
| EG(num_errors) = 0; | ||
| EG(errors) = NULL; | ||
| if ((type & E_FATAL_ERRORS) && !(type & E_DONT_BAIL) && EG(errors).size) { | ||
| uint32_t num_errors = EG(errors).size; | ||
| uint32_t cap_errors = EG(errors).capacity; | ||
| zend_error_info **errors = EG(errors).errors; | ||
|
Member
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. Ditto |
||
| EG(errors).size = 0; | ||
|
|
||
| bool orig_record_errors = EG(record_errors); | ||
| EG(record_errors) = false; | ||
|
|
@@ -1477,8 +1478,9 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( | |
|
|
||
| EG(user_error_handler_error_reporting) = orig_user_error_handler_error_reporting; | ||
| EG(record_errors) = orig_record_errors; | ||
| EG(num_errors) = num_errors; | ||
| EG(errors) = errors; | ||
| EG(errors).size = num_errors; | ||
| EG(errors).capacity = cap_errors; | ||
| EG(errors).errors = errors; | ||
| } | ||
|
|
||
| if (EG(record_errors)) { | ||
|
|
@@ -1487,12 +1489,13 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( | |
| info->lineno = error_lineno; | ||
| info->filename = zend_string_copy(error_filename); | ||
| info->message = zend_string_copy(message); | ||
|
|
||
| /* This is very inefficient for a large number of errors. | ||
| * Use pow2 realloc if it becomes a problem. */ | ||
| EG(num_errors)++; | ||
| EG(errors) = erealloc(EG(errors), sizeof(zend_error_info*) * EG(num_errors)); | ||
| EG(errors)[EG(num_errors)-1] = info; | ||
| EG(errors).size++; | ||
| if (EG(errors).size > EG(errors).capacity) { | ||
| uint32_t capacity = EG(errors).capacity ? EG(errors).capacity + (EG(errors).capacity >> 1) : 2; | ||
| EG(errors).errors = erealloc(EG(errors).errors, sizeof(zend_error_info *) * capacity); | ||
| EG(errors).capacity = capacity; | ||
| } | ||
| EG(errors).errors[EG(errors).size - 1] = info; | ||
|
|
||
| /* Do not process non-fatal recorded error */ | ||
| if (!(type & E_FATAL_ERRORS) || (type & E_DONT_BAIL)) { | ||
|
|
@@ -1575,17 +1578,20 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( | |
| } | ||
|
|
||
| orig_record_errors = EG(record_errors); | ||
| orig_num_errors = EG(num_errors); | ||
| orig_errors = EG(errors); | ||
| EG(record_errors) = false; | ||
| EG(num_errors) = 0; | ||
| EG(errors) = NULL; | ||
|
|
||
| orig_num_errors = EG(errors).size; | ||
| orig_cap_errors = EG(errors).capacity; | ||
| orig_errors = EG(errors).errors; | ||
| memset(&EG(errors), 0, sizeof(EG(errors))); | ||
|
|
||
| res = call_user_function(CG(function_table), NULL, &orig_user_error_handler, &retval, 4, params); | ||
|
|
||
| EG(record_errors) = orig_record_errors; | ||
| EG(num_errors) = orig_num_errors; | ||
| EG(errors) = orig_errors; | ||
|
|
||
| EG(errors).capacity = orig_cap_errors; | ||
| EG(errors).size = orig_num_errors; | ||
| EG(errors).errors = orig_errors; | ||
|
|
||
| if (res == SUCCESS) { | ||
| if (Z_TYPE(retval) != IS_UNDEF) { | ||
|
|
@@ -1780,8 +1786,7 @@ ZEND_API void zend_begin_record_errors(void) | |
| { | ||
| ZEND_ASSERT(!EG(record_errors) && "Error recording already enabled"); | ||
| EG(record_errors) = true; | ||
| EG(num_errors) = 0; | ||
| EG(errors) = NULL; | ||
| EG(errors).size = 0; | ||
| } | ||
|
|
||
| ZEND_API void zend_emit_recorded_errors_ex(uint32_t num_errors, zend_error_info **errors) | ||
|
|
@@ -1795,24 +1800,21 @@ ZEND_API void zend_emit_recorded_errors_ex(uint32_t num_errors, zend_error_info | |
| ZEND_API void zend_emit_recorded_errors(void) | ||
| { | ||
| EG(record_errors) = false; | ||
| zend_emit_recorded_errors_ex(EG(num_errors), EG(errors)); | ||
| zend_emit_recorded_errors_ex(EG(errors).size, EG(errors).errors); | ||
| } | ||
|
|
||
| ZEND_API void zend_free_recorded_errors(void) | ||
| { | ||
| if (!EG(num_errors)) { | ||
| return; | ||
| } | ||
|
Comment on lines
-1803
to
-1805
Member
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. We could keep this check to avoid the memset() and other checks when there are not errors |
||
|
|
||
| for (uint32_t i = 0; i < EG(num_errors); i++) { | ||
| zend_error_info *info = EG(errors)[i]; | ||
| for (uint32_t i = 0; i < EG(errors).size; i++) { | ||
| zend_error_info *info = EG(errors).errors[i]; | ||
| zend_string_release(info->filename); | ||
| zend_string_release(info->message); | ||
| efree(info); | ||
| efree_size(info, sizeof(zend_error_info)); | ||
| } | ||
| if (EG(errors).errors) { | ||
| efree(EG(errors).errors); | ||
| } | ||
| efree(EG(errors)); | ||
| EG(errors) = NULL; | ||
| EG(num_errors) = 0; | ||
| memset(&EG(errors), 0, sizeof(EG(errors))); | ||
| } | ||
|
|
||
| ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format, ...) /* {{{ */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -74,13 +74,20 @@ typedef struct _zend_vm_stack *zend_vm_stack; | |||||||||||||||||||||
| typedef struct _zend_ini_entry zend_ini_entry; | ||||||||||||||||||||||
| typedef struct _zend_fiber_context zend_fiber_context; | ||||||||||||||||||||||
| typedef struct _zend_fiber zend_fiber; | ||||||||||||||||||||||
| typedef struct _zend_error_info zend_error_info; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| typedef enum { | ||||||||||||||||||||||
| ZEND_MEMOIZE_NONE, | ||||||||||||||||||||||
| ZEND_MEMOIZE_COMPILE, | ||||||||||||||||||||||
| ZEND_MEMOIZE_FETCH, | ||||||||||||||||||||||
| } zend_memoize_mode; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| struct zend_err_buf { | ||||||||||||||||||||||
| uint32_t size; | ||||||||||||||||||||||
| uint32_t capacity; | ||||||||||||||||||||||
| zend_error_info **errors; | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
|
Member
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. Nit: we rarely use structs directly without a typedef:
Suggested change
(Then use |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| struct _zend_compiler_globals { | ||||||||||||||||||||||
| zend_stack loop_var_stack; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
@@ -298,8 +305,7 @@ struct _zend_executor_globals { | |||||||||||||||||||||
| * and their processing is delayed until zend_emit_recorded_errors() | ||||||||||||||||||||||
| * is called or a fatal diagnostic is emitted. */ | ||||||||||||||||||||||
| bool record_errors; | ||||||||||||||||||||||
| uint32_t num_errors; | ||||||||||||||||||||||
| zend_error_info **errors; | ||||||||||||||||||||||
| struct zend_err_buf errors; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /* Override filename or line number of thrown errors and exceptions */ | ||||||||||||||||||||||
| zend_string *filename_override; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
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.
Unexpected white space change