@@ -80,6 +80,8 @@ static char *zend_version_info;
8080static uint32_t zend_version_info_length ;
8181#define ZEND_CORE_VERSION_INFO "Zend Engine v" ZEND_VERSION ", Copyright (c) Zend Technologies\n"
8282#define PRINT_ZVAL_INDENT 4
83+ #define ZEND_ERR_BUF_SIZE (capacity ) \
84+ (XtOffsetOf(struct zend_err_buf, buf) + sizeof(zend_error_info *) * (capacity))
8385
8486/* true multithread-shared globals */
8587ZEND_API zend_class_entry * zend_standard_class_def = NULL ;
@@ -642,6 +644,13 @@ static FILE *zend_fopen_wrapper(zend_string *filename, zend_string **opened_path
642644}
643645/* }}} */
644646
647+ static void zend_init_errors_buf (zend_executor_globals * eg )
648+ {
649+ eg -> errors = pemalloc (ZEND_ERR_BUF_SIZE (2 ), true);
650+ eg -> errors -> capacity = 2 ;
651+ eg -> errors -> size = 0 ;
652+ }
653+
645654#ifdef ZTS
646655static bool short_tags_default = true;
647656static uint32_t compiler_options_default = ZEND_COMPILE_DEFAULT ;
@@ -833,8 +842,7 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{
833842#endif
834843 executor_globals -> flags = EG_FLAGS_INITIAL ;
835844 executor_globals -> record_errors = false;
836- executor_globals -> num_errors = 0 ;
837- executor_globals -> errors = NULL ;
845+ zend_init_errors_buf (executor_globals );
838846 executor_globals -> filename_override = NULL ;
839847 executor_globals -> lineno_override = -1 ;
840848#ifdef ZEND_CHECK_STACK_LIMIT
@@ -869,6 +877,8 @@ static void executor_globals_dtor(zend_executor_globals *executor_globals) /* {{
869877 zend_hash_destroy (executor_globals -> zend_constants );
870878 free (executor_globals -> zend_constants );
871879 }
880+
881+ pefree (executor_globals -> errors , true);
872882}
873883/* }}} */
874884
@@ -1065,6 +1075,7 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */
10651075 zend_init_rsrc_plist ();
10661076 zend_init_exception_op ();
10671077 zend_init_call_trampoline_op ();
1078+ zend_init_errors_buf (& executor_globals );
10681079#endif
10691080
10701081 zend_ini_startup ();
@@ -1147,6 +1158,7 @@ zend_result zend_post_startup(void) /* {{{ */
11471158 free (EG (zend_constants ));
11481159 EG (zend_constants ) = NULL ;
11491160
1161+ pefree (executor_globals -> errors , true);
11501162 executor_globals_ctor (executor_globals );
11511163 global_persistent_list = & EG (persistent_list );
11521164 zend_copy_ini_directives ();
@@ -1224,6 +1236,7 @@ void zend_shutdown(void) /* {{{ */
12241236 pefree (CG (internal_run_time_cache ), 1 );
12251237 CG (internal_run_time_cache ) = NULL ;
12261238 }
1239+ pefree (EG (errors ), true);
12271240#endif
12281241 zend_map_ptr_static_last = 0 ;
12291242 zend_map_ptr_static_size = 0 ;
@@ -1446,8 +1459,8 @@ ZEND_API ZEND_COLD void zend_error_zstr_at(
14461459 zend_stack delayed_oplines_stack ;
14471460 int type = orig_type & E_ALL ;
14481461 bool orig_record_errors ;
1449- uint32_t orig_num_errors ;
1450- zend_error_info * * orig_errors ;
1462+ uint32_t orig_num_errors = 0 ;
1463+ uint32_t orig_cap_errors = 0 ;
14511464 zend_result res ;
14521465
14531466 /* If we're executing a function during SCCP, count any warnings that may be emitted,
@@ -1459,11 +1472,11 @@ ZEND_API ZEND_COLD void zend_error_zstr_at(
14591472 }
14601473
14611474 /* Emit any delayed error before handling fatal error */
1462- if ((type & E_FATAL_ERRORS ) && !(type & E_DONT_BAIL ) && EG (num_errors )) {
1463- uint32_t num_errors = EG (num_errors );
1464- zend_error_info * * errors = EG (errors );
1465- EG ( num_errors ) = 0 ;
1466- EG (errors ) = NULL ;
1475+ if ((type & E_FATAL_ERRORS ) && !(type & E_DONT_BAIL ) && EG (errors -> size )) {
1476+ uint32_t num_errors = EG (errors -> size );
1477+ uint32_t cap_errors = EG (errors -> capacity );
1478+ zend_error_info * * errors = EG ( errors -> buf ) ;
1479+ EG (errors -> size ) = 0 ;
14671480
14681481 bool orig_record_errors = EG (record_errors );
14691482 EG (record_errors ) = false;
@@ -1477,8 +1490,8 @@ ZEND_API ZEND_COLD void zend_error_zstr_at(
14771490
14781491 EG (user_error_handler_error_reporting ) = orig_user_error_handler_error_reporting ;
14791492 EG (record_errors ) = orig_record_errors ;
1480- EG (num_errors ) = num_errors ;
1481- EG (errors ) = errors ;
1493+ EG (errors -> size ) = num_errors ;
1494+ EG (errors -> capacity ) = cap_errors ;
14821495 }
14831496
14841497 if (EG (record_errors )) {
@@ -1487,12 +1500,14 @@ ZEND_API ZEND_COLD void zend_error_zstr_at(
14871500 info -> lineno = error_lineno ;
14881501 info -> filename = zend_string_copy (error_filename );
14891502 info -> message = zend_string_copy (message );
1490-
1491- /* This is very inefficient for a large number of errors.
1492- * Use pow2 realloc if it becomes a problem. */
1493- EG (num_errors )++ ;
1494- EG (errors ) = erealloc (EG (errors ), sizeof (zend_error_info * ) * EG (num_errors ));
1495- EG (errors )[EG (num_errors )- 1 ] = info ;
1503+ EG (errors -> size )++ ;
1504+ if (EG (errors -> size ) >= EG (errors -> capacity )) {
1505+ // not sure we can get high number of errors so safe `might be` over cautious here
1506+ uint32_t capacity = EG (errors -> capacity ) + (EG (errors -> capacity ) >> 1 );
1507+ EG (errors ) = safe_perealloc (EG (errors ), sizeof (zend_error_info * ), capacity , XtOffsetOf (struct zend_err_buf , buf ), true);
1508+ EG (errors -> capacity ) = capacity ;
1509+ }
1510+ EG (errors -> buf )[EG (errors -> size )- 1 ] = info ;
14961511
14971512 /* Do not process non-fatal recorded error */
14981513 if (!(type & E_FATAL_ERRORS ) || (type & E_DONT_BAIL )) {
@@ -1575,17 +1590,18 @@ ZEND_API ZEND_COLD void zend_error_zstr_at(
15751590 }
15761591
15771592 orig_record_errors = EG (record_errors );
1578- orig_num_errors = EG (num_errors );
1579- orig_errors = EG (errors );
15801593 EG (record_errors ) = false;
1581- EG (num_errors ) = 0 ;
1582- EG (errors ) = NULL ;
1594+
1595+ orig_num_errors = EG (errors -> size );
1596+ orig_cap_errors = EG (errors -> capacity );
1597+ EG (errors -> size ) = 0 ;
15831598
15841599 res = call_user_function (CG (function_table ), NULL , & orig_user_error_handler , & retval , 4 , params );
15851600
15861601 EG (record_errors ) = orig_record_errors ;
1587- EG (num_errors ) = orig_num_errors ;
1588- EG (errors ) = orig_errors ;
1602+
1603+ EG (errors -> capacity ) = orig_cap_errors ;
1604+ EG (errors -> size ) = orig_num_errors ;
15891605
15901606 if (res == SUCCESS ) {
15911607 if (Z_TYPE (retval ) != IS_UNDEF ) {
@@ -1780,8 +1796,7 @@ ZEND_API void zend_begin_record_errors(void)
17801796{
17811797 ZEND_ASSERT (!EG (record_errors ) && "Error recording already enabled" );
17821798 EG (record_errors ) = true;
1783- EG (num_errors ) = 0 ;
1784- EG (errors ) = NULL ;
1799+ EG (errors -> size ) = 0 ;
17851800}
17861801
17871802ZEND_API void zend_emit_recorded_errors_ex (uint32_t num_errors , zend_error_info * * errors )
@@ -1795,24 +1810,22 @@ ZEND_API void zend_emit_recorded_errors_ex(uint32_t num_errors, zend_error_info
17951810ZEND_API void zend_emit_recorded_errors (void )
17961811{
17971812 EG (record_errors ) = false;
1798- zend_emit_recorded_errors_ex (EG (num_errors ), EG (errors ));
1813+ zend_emit_recorded_errors_ex (EG (errors -> size ), EG (errors -> buf ));
17991814}
18001815
18011816ZEND_API void zend_free_recorded_errors (void )
18021817{
1803- if (!EG (num_errors )) {
1818+ if (!EG (errors -> size )) {
18041819 return ;
18051820 }
18061821
1807- for (uint32_t i = 0 ; i < EG (num_errors ); i ++ ) {
1808- zend_error_info * info = EG (errors )[i ];
1822+ for (uint32_t i = 0 ; i < EG (errors -> size ); i ++ ) {
1823+ zend_error_info * info = EG (errors -> buf )[i ];
18091824 zend_string_release (info -> filename );
18101825 zend_string_release (info -> message );
1811- efree (info );
1826+ efree_size (info , sizeof ( zend_error_info ) );
18121827 }
1813- efree (EG (errors ));
1814- EG (errors ) = NULL ;
1815- EG (num_errors ) = 0 ;
1828+ EG (errors -> size ) = 0 ;
18161829}
18171830
18181831ZEND_API ZEND_COLD void zend_throw_error (zend_class_entry * exception_ce , const char * format , ...) /* {{{ */
@@ -2020,12 +2033,12 @@ ZEND_API zend_result zend_execute_scripts(int type, zval *retval, int file_count
20202033}
20212034/* }}} */
20222035
2023- #define COMPILED_STRING_DESCRIPTION_FORMAT "%s(%d ) : %s"
2036+ #define COMPILED_STRING_DESCRIPTION_FORMAT "%s(%u ) : %s"
20242037
20252038ZEND_API char * zend_make_compiled_string_description (const char * name ) /* {{{ */
20262039{
20272040 const char * cur_filename ;
2028- int cur_lineno ;
2041+ uint32_t cur_lineno ;
20292042 char * compiled_string_description ;
20302043
20312044 if (zend_is_compiling ()) {
0 commit comments