diff options
Diffstat (limited to 'Zend/zend_exceptions.c')
-rw-r--r-- | Zend/zend_exceptions.c | 171 |
1 files changed, 128 insertions, 43 deletions
diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 655542fc30..7070934426 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -30,8 +30,11 @@ #include "zend_dtrace.h" #include "zend_smart_str.h" +static zend_class_entry *base_exception_ce; static zend_class_entry *default_exception_ce; static zend_class_entry *error_exception_ce; +static zend_class_entry *engine_exception_ce; +static zend_class_entry *parse_exception_ce; static zend_object_handlers default_exception_handlers; ZEND_API void (*zend_throw_exception_hook)(zval *ex); @@ -43,16 +46,16 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo return; } ZVAL_OBJ(&tmp, add_previous); - if (!instanceof_function(Z_OBJCE(tmp), default_exception_ce)) { + if (!instanceof_function(Z_OBJCE(tmp), base_exception_ce)) { zend_error(E_ERROR, "Cannot set non exception as previous exception"); return; } ZVAL_OBJ(&zv, exception); pzv = &zv; do { - previous = zend_read_property(default_exception_ce, pzv, "previous", sizeof("previous")-1, 1, &rv); + previous = zend_read_property(base_exception_ce, pzv, "previous", sizeof("previous")-1, 1, &rv); if (Z_TYPE_P(previous) == IS_NULL) { - zend_update_property(default_exception_ce, pzv, "previous", sizeof("previous")-1, &tmp); + zend_update_property(base_exception_ce, pzv, "previous", sizeof("previous")-1, &tmp); GC_REFCOUNT(add_previous)--; return; } @@ -106,6 +109,9 @@ ZEND_API void zend_throw_exception_internal(zval *exception) /* {{{ */ } } if (!EG(current_execute_data)) { + if (exception && Z_OBJCE_P(exception) == parse_exception_ce) { + return; + } if(EG(exception)) { zend_exception_error(EG(exception), E_ERROR); } @@ -157,12 +163,21 @@ static zend_object *zend_default_exception_new_ex(zend_class_entry *class_type, object_properties_init(object, class_type); - zend_fetch_debug_backtrace(&trace, skip_top_traces, 0, 0); + if (EG(current_execute_data)) { + zend_fetch_debug_backtrace(&trace, skip_top_traces, 0, 0); + } else { + array_init(&trace); + } Z_SET_REFCOUNT(trace, 0); - zend_update_property_string(default_exception_ce, &obj, "file", sizeof("file")-1, zend_get_executed_filename()); - zend_update_property_long(default_exception_ce, &obj, "line", sizeof("line")-1, zend_get_executed_lineno()); - zend_update_property(default_exception_ce, &obj, "trace", sizeof("trace")-1, &trace); + if (EXPECTED(class_type != parse_exception_ce)) { + zend_update_property_string(base_exception_ce, &obj, "file", sizeof("file")-1, zend_get_executed_filename()); + zend_update_property_long(base_exception_ce, &obj, "line", sizeof("line")-1, zend_get_executed_lineno()); + } else { + zend_update_property_string(base_exception_ce, &obj, "file", sizeof("file")-1, zend_get_compiled_filename()->val); + zend_update_property_long(base_exception_ce, &obj, "line", sizeof("line")-1, zend_get_compiled_lineno()); + } + zend_update_property(base_exception_ce, &obj, "trace", sizeof("trace")-1, &trace); return object; } @@ -198,22 +213,22 @@ ZEND_METHOD(exception, __construct) zval *object, *previous = NULL; int argc = ZEND_NUM_ARGS(); - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc, "|SlO!", &message, &code, &previous, default_exception_ce) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc, "|SlO!", &message, &code, &previous, base_exception_ce) == FAILURE) { zend_error(E_ERROR, "Wrong parameters for Exception([string $exception [, long $code [, Exception $previous = NULL]]])"); } object = getThis(); if (message) { - zend_update_property_str(default_exception_ce, object, "message", sizeof("message")-1, message); + zend_update_property_str(base_exception_ce, object, "message", sizeof("message")-1, message); } if (code) { - zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code); + zend_update_property_long(base_exception_ce, object, "code", sizeof("code")-1, code); } if (previous) { - zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous); + zend_update_property(base_exception_ce, object, "previous", sizeof("previous")-1, previous); } } /* }}} */ @@ -228,32 +243,32 @@ ZEND_METHOD(error_exception, __construct) int argc = ZEND_NUM_ARGS(); size_t message_len, filename_len; - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc, "|sllslO!", &message, &message_len, &code, &severity, &filename, &filename_len, &lineno, &previous, default_exception_ce) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc, "|sllslO!", &message, &message_len, &code, &severity, &filename, &filename_len, &lineno, &previous, base_exception_ce) == FAILURE) { zend_error(E_ERROR, "Wrong parameters for ErrorException([string $exception [, long $code, [ long $severity, [ string $filename, [ long $lineno [, Exception $previous = NULL]]]]]])"); } object = getThis(); if (message) { - zend_update_property_string(default_exception_ce, object, "message", sizeof("message")-1, message); + zend_update_property_string(base_exception_ce, object, "message", sizeof("message")-1, message); } if (code) { - zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code); + zend_update_property_long(base_exception_ce, object, "code", sizeof("code")-1, code); } if (previous) { - zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous); + zend_update_property(base_exception_ce, object, "previous", sizeof("previous")-1, previous); } - zend_update_property_long(default_exception_ce, object, "severity", sizeof("severity")-1, severity); + zend_update_property_long(base_exception_ce, object, "severity", sizeof("severity")-1, severity); if (argc >= 4) { - zend_update_property_string(default_exception_ce, object, "file", sizeof("file")-1, filename); + zend_update_property_string(base_exception_ce, object, "file", sizeof("file")-1, filename); if (argc < 5) { lineno = 0; /* invalidate lineno */ } - zend_update_property_long(default_exception_ce, object, "line", sizeof("line")-1, lineno); + zend_update_property_long(base_exception_ce, object, "line", sizeof("line")-1, lineno); } } /* }}} */ @@ -264,9 +279,9 @@ ZEND_METHOD(error_exception, __construct) } #define GET_PROPERTY(object, name) \ - zend_read_property(default_exception_ce, (object), name, sizeof(name) - 1, 0, &rv) + zend_read_property(base_exception_ce, (object), name, sizeof(name) - 1, 0, &rv) #define GET_PROPERTY_SILENT(object, name) \ - zend_read_property(default_exception_ce, (object), name, sizeof(name) - 1, 1, &rv) + zend_read_property(base_exception_ce, (object), name, sizeof(name) - 1, 1, &rv) /* {{{ proto string Exception::getFile() Get the file in which the exception occurred */ @@ -538,7 +553,7 @@ ZEND_METHOD(exception, getTraceAsString) DEFAULT_0_PARAMS; - trace = zend_read_property(default_exception_ce, getThis(), "trace", sizeof("trace")-1, 1, &rv); + trace = zend_read_property(base_exception_ce, getThis(), "trace", sizeof("trace")-1, 1, &rv); ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(trace), index, frame) { if (Z_TYPE_P(frame) != IS_ARRAY) { zend_error(E_WARNING, "Expected array for frame %pu", index); @@ -656,7 +671,7 @@ ZEND_METHOD(exception, __toString) /* We store the result in the private property string so we can access * the result in uncaught exception handlers without memleaks. */ - zend_update_property_str(default_exception_ce, getThis(), "string", sizeof("string")-1, str); + zend_update_property_str(base_exception_ce, getThis(), "string", sizeof("string")-1, str); RETURN_STR(str); } @@ -711,25 +726,64 @@ static const zend_function_entry error_exception_functions[] = { void zend_register_default_exception(void) /* {{{ */ { zend_class_entry ce; + zend_property_info *prop; - INIT_CLASS_ENTRY(ce, "Exception", default_exception_functions); - default_exception_ce = zend_register_internal_class(&ce); - default_exception_ce->create_object = zend_default_exception_new; + INIT_CLASS_ENTRY(ce, "BaseException", default_exception_functions); + base_exception_ce = zend_register_internal_class(&ce); + base_exception_ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; + base_exception_ce->create_object = NULL; memcpy(&default_exception_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); default_exception_handlers.clone_obj = NULL; - zend_declare_property_string(default_exception_ce, "message", sizeof("message")-1, "", ZEND_ACC_PROTECTED); - zend_declare_property_string(default_exception_ce, "string", sizeof("string")-1, "", ZEND_ACC_PRIVATE); - zend_declare_property_long(default_exception_ce, "code", sizeof("code")-1, 0, ZEND_ACC_PROTECTED); - zend_declare_property_null(default_exception_ce, "file", sizeof("file")-1, ZEND_ACC_PROTECTED); - zend_declare_property_null(default_exception_ce, "line", sizeof("line")-1, ZEND_ACC_PROTECTED); - zend_declare_property_null(default_exception_ce, "trace", sizeof("trace")-1, ZEND_ACC_PRIVATE); - zend_declare_property_null(default_exception_ce, "previous", sizeof("previous")-1, ZEND_ACC_PRIVATE); + zend_declare_property_string(base_exception_ce, "message", sizeof("message")-1, "", ZEND_ACC_PROTECTED); + zend_declare_property_string(base_exception_ce, "string", sizeof("string")-1, "", ZEND_ACC_PRIVATE); + zend_declare_property_long(base_exception_ce, "code", sizeof("code")-1, 0, ZEND_ACC_PROTECTED); + zend_declare_property_null(base_exception_ce, "file", sizeof("file")-1, ZEND_ACC_PROTECTED); + zend_declare_property_null(base_exception_ce, "line", sizeof("line")-1, ZEND_ACC_PROTECTED); + zend_declare_property_null(base_exception_ce, "trace", sizeof("trace")-1, ZEND_ACC_PRIVATE); + zend_declare_property_null(base_exception_ce, "previous", sizeof("previous")-1, ZEND_ACC_PRIVATE); + + INIT_CLASS_ENTRY(ce, "Exception", NULL); + default_exception_ce = zend_register_internal_class_ex(&ce, base_exception_ce); + default_exception_ce->create_object = zend_default_exception_new; + + /* A trick, to make visible prvate properties of BaseException */ + ZEND_HASH_FOREACH_PTR(&default_exception_ce->properties_info, prop) { + if (prop->flags & ZEND_ACC_SHADOW) { + if (prop->name->len == sizeof("\0BaseException\0string")-1) { + prop->flags &= ~ZEND_ACC_SHADOW; + prop->flags |= ZEND_ACC_PRIVATE; + prop->ce = default_exception_ce; + } else if (prop->name->len == sizeof("\0BaseException\0trace")-1) { + prop->flags &= ~ZEND_ACC_SHADOW; + prop->flags |= ZEND_ACC_PRIVATE; + prop->ce = default_exception_ce; + } else if (prop->name->len == sizeof("\0BaseException\0previous")-1) { + prop->flags &= ~ZEND_ACC_SHADOW; + prop->flags |= ZEND_ACC_PRIVATE; + prop->ce = default_exception_ce; + } + } + } ZEND_HASH_FOREACH_END(); INIT_CLASS_ENTRY(ce, "ErrorException", error_exception_functions); error_exception_ce = zend_register_internal_class_ex(&ce, default_exception_ce); error_exception_ce->create_object = zend_error_exception_new; zend_declare_property_long(error_exception_ce, "severity", sizeof("severity")-1, E_ERROR, ZEND_ACC_PROTECTED); + + INIT_CLASS_ENTRY(ce, "EngineException", NULL); + engine_exception_ce = zend_register_internal_class_ex(&ce, base_exception_ce); + engine_exception_ce->create_object = zend_default_exception_new; + + INIT_CLASS_ENTRY(ce, "ParseException", NULL); + parse_exception_ce = zend_register_internal_class_ex(&ce, base_exception_ce); + parse_exception_ce->create_object = zend_default_exception_new; +} +/* }}} */ + +ZEND_API zend_class_entry *zend_exception_get_base(void) /* {{{ */ +{ + return base_exception_ce; } /* }}} */ @@ -745,12 +799,25 @@ ZEND_API zend_class_entry *zend_get_error_exception(void) /* {{{ */ } /* }}} */ +ZEND_API zend_class_entry *zend_get_engine_exception(void) /* {{{ */ +{ + return engine_exception_ce; +} +/* }}} */ + +ZEND_API zend_class_entry *zend_get_parse_exception(void) /* {{{ */ +{ + return parse_exception_ce; +} +/* }}} */ + + ZEND_API zend_object *zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code) /* {{{ */ { zval ex; if (exception_ce) { - if (!instanceof_function(exception_ce, default_exception_ce)) { + if (!instanceof_function(exception_ce, base_exception_ce)) { zend_error(E_NOTICE, "Exceptions must be derived from the Exception base class"); exception_ce = default_exception_ce; } @@ -761,10 +828,10 @@ ZEND_API zend_object *zend_throw_exception(zend_class_entry *exception_ce, const if (message) { - zend_update_property_string(default_exception_ce, &ex, "message", sizeof("message")-1, message); + zend_update_property_string(base_exception_ce, &ex, "message", sizeof("message")-1, message); } if (code) { - zend_update_property_long(default_exception_ce, &ex, "code", sizeof("code")-1, code); + zend_update_property_long(base_exception_ce, &ex, "code", sizeof("code")-1, code); } zend_throw_exception_internal(&ex); @@ -792,7 +859,7 @@ ZEND_API zend_object *zend_throw_error_exception(zend_class_entry *exception_ce, zval ex; zend_object *obj = zend_throw_exception(exception_ce, message, code); ZVAL_OBJ(&ex, obj); - zend_update_property_long(default_exception_ce, &ex, "severity", sizeof("severity")-1, severity); + zend_update_property_long(base_exception_ce, &ex, "severity", sizeof("severity")-1, severity); return obj; } /* }}} */ @@ -807,27 +874,45 @@ static void zend_error_va(int type, const char *file, uint lineno, const char *f } /* }}} */ +static void zend_error_helper(int type, const char *filename, const uint lineno, const char *format, ...) +{ + va_list va; + + va_start(va, format); + zend_error_cb(type, filename, lineno, format, va); + va_end(va); +} + /* This function doesn't return if it uses E_ERROR */ ZEND_API void zend_exception_error(zend_object *ex, int severity) /* {{{ */ { - zval exception; + zval exception, rv; zend_class_entry *ce_exception; ZVAL_OBJ(&exception, ex); ce_exception = Z_OBJCE(exception); - if (instanceof_function(ce_exception, default_exception_ce)) { + EG(exception) = NULL; + if (ce_exception == parse_exception_ce || ce_exception == engine_exception_ce) { + zend_string *message = zval_get_string(GET_PROPERTY(&exception, "message")); + zend_string *file = zval_get_string(GET_PROPERTY_SILENT(&exception, "file")); + zend_long line = zval_get_long(GET_PROPERTY_SILENT(&exception, "line")); + zend_long code = zval_get_long(GET_PROPERTY_SILENT(&exception, "code")); + + zend_error_helper(code, file->val, line, "%s", message->val); + zend_string_release(file); + zend_string_release(message); + OBJ_RELEASE(ex); + } else if (instanceof_function(ce_exception, base_exception_ce)) { zval tmp, rv; zend_string *str, *file = NULL; zend_long line = 0; - EG(exception) = NULL; - zend_call_method_with_0_params(&exception, ce_exception, NULL, "__tostring", &tmp); if (!EG(exception)) { if (Z_TYPE(tmp) != IS_STRING) { zend_error(E_WARNING, "%s::__toString() must return a string", ce_exception->name->val); } else { - zend_update_property_string(default_exception_ce, &exception, "string", sizeof("string")-1, EG(exception) ? ce_exception->name->val : Z_STRVAL(tmp)); + zend_update_property_string(base_exception_ce, &exception, "string", sizeof("string")-1, EG(exception) ? ce_exception->name->val : Z_STRVAL(tmp)); } } zval_ptr_dtor(&tmp); @@ -837,7 +922,7 @@ ZEND_API void zend_exception_error(zend_object *ex, int severity) /* {{{ */ ZVAL_OBJ(&zv, EG(exception)); /* do the best we can to inform about the inner exception */ - if (instanceof_function(ce_exception, default_exception_ce)) { + if (instanceof_function(ce_exception, base_exception_ce)) { file = zval_get_string(GET_PROPERTY_SILENT(&zv, "file")); line = zval_get_long(GET_PROPERTY_SILENT(&zv, "line")); } @@ -876,7 +961,7 @@ ZEND_API void zend_throw_exception_object(zval *exception) /* {{{ */ exception_ce = Z_OBJCE_P(exception); - if (!exception_ce || !instanceof_function(exception_ce, default_exception_ce)) { + if (!exception_ce || !instanceof_function(exception_ce, base_exception_ce)) { zend_error(E_ERROR, "Exceptions must be valid objects derived from the Exception base class"); } zend_throw_exception_internal(exception); |