Skip to content

Commit 100a1e8

Browse files
committed
Convert exception during inheritance to fatal error
Now that inheritance can throw deprecations again, these may be converted to exception by a custom error handler. In this case we need to convert the exception to a fatal error, as inheritance cannot safely throw in the general case.
1 parent 6e477d2 commit 100a1e8

File tree

5 files changed

+43
-16
lines changed

5 files changed

+43
-16
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Deprecation promoted to exception should result in fatal error during inheritance
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(function($code, $message) {
7+
throw new Exception($message);
8+
});
9+
10+
$class = new class extends DateTime {
11+
public function getTimezone() {}
12+
};
13+
14+
?>
15+
--EXPECTF--
16+
Fatal error: During inheritance of DateTime: Uncaught Exception: Declaration of DateTime@anonymous::getTimezone() should be compatible with DateTime::getTimezone(): DateTimeZone|false in %s:%d
17+
Stack trace:
18+
#0 %s(%d): {closure}(8192, 'Declaration of ...', '%s', 8)
19+
#1 {main} in %s on line %d

Zend/zend_exceptions.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,22 @@ ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *ex, int severit
968968
}
969969
/* }}} */
970970

971+
ZEND_NORETURN void zend_exception_uncaught_error(const char *format, ...) {
972+
va_list va;
973+
va_start(va, format);
974+
zend_string *prefix = zend_vstrpprintf(0, format, va);
975+
va_end(va);
976+
977+
ZEND_ASSERT(EG(exception));
978+
zval exception_zv;
979+
ZVAL_OBJ_COPY(&exception_zv, EG(exception));
980+
zend_clear_exception();
981+
982+
zend_string *exception_str = zval_get_string(&exception_zv);
983+
zend_error_noreturn(E_ERROR,
984+
"%s: Uncaught %s", ZSTR_VAL(prefix), ZSTR_VAL(exception_str));
985+
}
986+
971987
ZEND_API ZEND_COLD void zend_throw_exception_object(zval *exception) /* {{{ */
972988
{
973989
if (exception == NULL || Z_TYPE_P(exception) != IS_OBJECT) {

Zend/zend_exceptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ extern ZEND_API void (*zend_throw_exception_hook)(zend_object *ex);
6868

6969
/* show an exception using zend_error(severity,...), severity should be E_ERROR */
7070
ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *exception, int severity);
71+
ZEND_NORETURN void zend_exception_uncaught_error(const char *prefix, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2);
7172
ZEND_API zend_string *zend_trace_to_string(HashTable *trace, bool include_main);
7273

7374
ZEND_API ZEND_COLD void zend_throw_unwind_exit(void);

Zend/zend_execute_API.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,14 +1518,7 @@ zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, zend_string
15181518
}
15191519
if (EG(exception)) {
15201520
if (!(fetch_type & ZEND_FETCH_CLASS_EXCEPTION)) {
1521-
zend_string *exception_str;
1522-
zval exception_zv;
1523-
ZVAL_OBJ(&exception_zv, EG(exception));
1524-
Z_ADDREF(exception_zv);
1525-
zend_clear_exception();
1526-
exception_str = zval_get_string(&exception_zv);
1527-
zend_error_noreturn(E_ERROR,
1528-
"During class fetch: Uncaught %s", ZSTR_VAL(exception_str));
1521+
zend_exception_uncaught_error("During class fetch");
15291522
}
15301523
return NULL;
15311524
}

Zend/zend_inheritance.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,10 @@ static void ZEND_COLD emit_incompatible_method_error(
877877
zend_error_at(E_DEPRECATED, NULL, func_lineno(child),
878878
"Declaration of %s should be compatible with %s",
879879
ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
880+
if (EG(exception)) {
881+
zend_exception_uncaught_error(
882+
"During inheritance of %s", ZSTR_VAL(parent_scope->name));
883+
}
880884
}
881885
} else {
882886
zend_error_at(E_COMPILE_ERROR, NULL, func_lineno(child),
@@ -2454,14 +2458,8 @@ static void check_unrecoverable_load_failure(zend_class_entry *ce) {
24542458
|| ((ce->ce_flags & ZEND_ACC_IMMUTABLE)
24552459
&& CG(unlinked_uses)
24562460
&& zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t)ce) == SUCCESS)) {
2457-
zend_string *exception_str;
2458-
zval exception_zv;
2459-
ZEND_ASSERT(EG(exception) && "Exception must have been thrown");
2460-
ZVAL_OBJ_COPY(&exception_zv, EG(exception));
2461-
zend_clear_exception();
2462-
exception_str = zval_get_string(&exception_zv);
2463-
zend_error_noreturn(E_ERROR,
2464-
"During inheritance of %s with variance dependencies: Uncaught %s", ZSTR_VAL(ce->name), ZSTR_VAL(exception_str));
2461+
zend_exception_uncaught_error(
2462+
"During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name));
24652463
}
24662464
}
24672465

0 commit comments

Comments
 (0)