Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 48 additions & 35 deletions Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ static char *zend_version_info;
static uint32_t zend_version_info_length;
#define ZEND_CORE_VERSION_INFO "Zend Engine v" ZEND_VERSION ", Copyright (c) Zend Technologies\n"
#define PRINT_ZVAL_INDENT 4
#define ZEND_ERR_BUF_SIZE(capacity) \
(XtOffsetOf(struct zend_err_buf, buf) + sizeof(zend_error_info *) * (capacity))

/* true multithread-shared globals */
ZEND_API zend_class_entry *zend_standard_class_def = NULL;
Expand Down Expand Up @@ -642,6 +644,13 @@ static FILE *zend_fopen_wrapper(zend_string *filename, zend_string **opened_path
}
/* }}} */

static void zend_init_errors_buf(zend_executor_globals *eg)
{
eg->errors = pemalloc(ZEND_ERR_BUF_SIZE(2), true);
eg->errors->capacity = 2;
eg->errors->size = 0;
}

#ifdef ZTS
static bool short_tags_default = true;
static uint32_t compiler_options_default = ZEND_COMPILE_DEFAULT;
Expand Down Expand Up @@ -833,8 +842,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;
zend_init_errors_buf(executor_globals);
executor_globals->filename_override = NULL;
executor_globals->lineno_override = -1;
#ifdef ZEND_CHECK_STACK_LIMIT
Expand Down Expand Up @@ -869,6 +877,8 @@ static void executor_globals_dtor(zend_executor_globals *executor_globals) /* {{
zend_hash_destroy(executor_globals->zend_constants);
free(executor_globals->zend_constants);
}

pefree(executor_globals->errors, true);
}
/* }}} */

Expand Down Expand Up @@ -1065,6 +1075,7 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */
zend_init_rsrc_plist();
zend_init_exception_op();
zend_init_call_trampoline_op();
zend_init_errors_buf(&executor_globals);
#endif

zend_ini_startup();
Expand Down Expand Up @@ -1147,6 +1158,7 @@ zend_result zend_post_startup(void) /* {{{ */
free(EG(zend_constants));
EG(zend_constants) = NULL;

pefree(executor_globals->errors, true);
executor_globals_ctor(executor_globals);
global_persistent_list = &EG(persistent_list);
zend_copy_ini_directives();
Expand Down Expand Up @@ -1224,6 +1236,7 @@ void zend_shutdown(void) /* {{{ */
pefree(CG(internal_run_time_cache), 1);
CG(internal_run_time_cache) = NULL;
}
pefree(EG(errors), true);
#endif
zend_map_ptr_static_last = 0;
zend_map_ptr_static_size = 0;
Expand Down Expand Up @@ -1446,8 +1459,8 @@ 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_result res;

/* If we're executing a function during SCCP, count any warnings that may be emitted,
Expand All @@ -1459,11 +1472,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->buf);
EG(errors->size) = 0;

bool orig_record_errors = EG(record_errors);
EG(record_errors) = false;
Expand All @@ -1477,8 +1490,8 @@ 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;
}

if (EG(record_errors)) {
Expand All @@ -1487,12 +1500,14 @@ 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)) {
// not sure we can get high number of errors so safe `might be` over cautious here
uint32_t capacity = EG(errors->capacity) + (EG(errors->capacity) >> 1);
EG(errors) = safe_perealloc(EG(errors), sizeof(zend_error_info *), capacity, XtOffsetOf(struct zend_err_buf, buf), true);
EG(errors->capacity) = capacity;
}
EG(errors->buf)[EG(errors->size)-1] = info;

/* Do not process non-fatal recorded error */
if (!(type & E_FATAL_ERRORS) || (type & E_DONT_BAIL)) {
Expand Down Expand Up @@ -1575,17 +1590,18 @@ 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);
EG(errors->size) = 0;

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;

if (res == SUCCESS) {
if (Z_TYPE(retval) != IS_UNDEF) {
Expand Down Expand Up @@ -1780,8 +1796,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)
Expand All @@ -1795,24 +1810,22 @@ 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->buf));
}

ZEND_API void zend_free_recorded_errors(void)
{
if (!EG(num_errors)) {
if (!EG(errors->size)) {
return;
}

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->buf)[i];
zend_string_release(info->filename);
zend_string_release(info->message);
efree(info);
efree_size(info, sizeof(zend_error_info));
}
efree(EG(errors));
EG(errors) = NULL;
EG(num_errors) = 0;
EG(errors->size) = 0;
}

ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format, ...) /* {{{ */
Expand Down Expand Up @@ -2020,12 +2033,12 @@ ZEND_API zend_result zend_execute_scripts(int type, zval *retval, int file_count
}
/* }}} */

#define COMPILED_STRING_DESCRIPTION_FORMAT "%s(%d) : %s"
#define COMPILED_STRING_DESCRIPTION_FORMAT "%s(%u) : %s"

ZEND_API char *zend_make_compiled_string_description(const char *name) /* {{{ */
{
const char *cur_filename;
int cur_lineno;
uint32_t cur_lineno;
char *compiled_string_description;

if (zend_is_compiling()) {
Expand Down
3 changes: 1 addition & 2 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,7 @@ void init_executor(void) /* {{{ */
EG(get_gc_buffer).start = EG(get_gc_buffer).end = EG(get_gc_buffer).cur = NULL;

EG(record_errors) = false;
EG(num_errors) = 0;
EG(errors) = NULL;
EG(errors->size) = 0;

EG(filename_override) = NULL;
EG(lineno_override) = -1;
Expand Down
10 changes: 8 additions & 2 deletions Zend/zend_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *buf[1];
};

struct _zend_compiler_globals {
zend_stack loop_var_stack;

Expand Down Expand Up @@ -298,8 +305,6 @@ 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;

/* Override filename or line number of thrown errors and exceptions */
zend_string *filename_override;
Expand All @@ -322,6 +327,7 @@ struct _zend_executor_globals {
HashTable callable_convert_cache;

void *reserved[ZEND_MAX_RESERVED_RESOURCES];
struct zend_err_buf *errors;
};

#define EG_FLAGS_INITIAL (0)
Expand Down
20 changes: 10 additions & 10 deletions ext/opcache/ZendAccelerator.c
Original file line number Diff line number Diff line change
Expand Up @@ -1974,8 +1974,8 @@ static zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int

if (persistent_script) {
if (ZCG(accel_directives).record_warnings) {
persistent_script->num_warnings = EG(num_errors);
persistent_script->warnings = EG(errors);
persistent_script->num_warnings = EG(errors->size);
persistent_script->warnings = EG(errors->buf);
}

from_memory = false;
Expand Down Expand Up @@ -2199,8 +2199,8 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
from_shared_memory = false;
if (persistent_script) {
if (ZCG(accel_directives).record_warnings) {
persistent_script->num_warnings = EG(num_errors);
persistent_script->warnings = EG(errors);
persistent_script->num_warnings = EG(errors->size);
persistent_script->warnings = EG(errors->buf);
}

/* See GH-17246: we disable GC so that user code cannot be executed during the optimizer run. */
Expand Down Expand Up @@ -2428,7 +2428,7 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce,
}
ZCG(current_persistent_script) = &dummy;
zend_persist_class_entry_calc(ce);
zend_persist_warnings_calc(EG(num_errors), EG(errors));
zend_persist_warnings_calc(EG(errors->size), EG(errors->buf));
size = dummy.size;

zend_shared_alloc_clear_xlat_table();
Expand Down Expand Up @@ -2498,8 +2498,8 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce,
JIT_G(on) = jit_on_old;
#endif

entry->num_warnings = EG(num_errors);
entry->warnings = zend_persist_warnings(EG(num_errors), EG(errors));
entry->num_warnings = EG(errors->size);
entry->warnings = zend_persist_warnings(EG(errors->size), EG(errors->buf));
entry->next = proto->inheritance_cache;
proto->inheritance_cache = entry;

Expand Down Expand Up @@ -4133,9 +4133,9 @@ static void preload_link(void)
/* Remember the last error. */
zend_error_cb = orig_error_cb;
EG(record_errors) = false;
ZEND_ASSERT(EG(num_errors) > 0);
zend_hash_update_ptr(&errors, key, EG(errors)[EG(num_errors)-1]);
EG(num_errors)--;
ZEND_ASSERT(EG(errors->size) > 0);
zend_hash_update_ptr(&errors, key, EG(errors->buf)[EG(errors->size)-1]);
EG(errors->size)--;
} zend_end_try();
CG(in_compilation) = false;
CG(compiled_filename) = NULL;
Expand Down
Loading