php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
zend_exceptions.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@php.net> |
16 | Marcus Boerger <helly@php.net> |
17 | Sterling Hughes <sterling@php.net> |
18 | Zeev Suraski <zeev@php.net> |
19 +----------------------------------------------------------------------+
20*/
21
22#include "zend.h"
23#include "zend_API.h"
25#include "zend_interfaces.h"
26#include "zend_exceptions.h"
27#include "zend_vm.h"
28#include "zend_dtrace.h"
29#include "zend_smart_str.h"
31#include "zend_observer.h"
32
46
47/* Internal pseudo-exception that is not exposed to userland. Throwing this exception *does not* execute finally blocks. */
48static zend_class_entry zend_ce_unwind_exit;
49
50/* Internal pseudo-exception that is not exposed to userland. Throwing this exception *does* execute finally blocks. */
51static zend_class_entry zend_ce_graceful_exit;
52
54
55static zend_object_handlers default_exception_handlers;
56
57/* {{{ zend_implement_throwable */
58static int zend_implement_throwable(zend_class_entry *interface, zend_class_entry *class_type)
59{
60 /* zend_ce_exception and zend_ce_error may not be initialized yet when this is called (e.g when
61 * implementing Throwable for Exception itself). Perform a manual inheritance check. */
62 zend_class_entry *root = class_type;
63 while (root->parent) {
64 root = root->parent;
65 }
66 if (zend_string_equals_literal(root->name, "Exception")
67 || zend_string_equals_literal(root->name, "Error")) {
68 return SUCCESS;
69 }
70
71 bool can_extend = (class_type->ce_flags & ZEND_ACC_ENUM) == 0;
72
74 can_extend
75 ? "%s %s cannot implement interface %s, extend Exception or Error instead"
76 : "%s %s cannot implement interface %s",
77 zend_get_object_type_uc(class_type),
78 ZSTR_VAL(class_type->name),
79 ZSTR_VAL(interface->name));
80 return FAILURE;
81}
82/* }}} */
83
84static inline zend_class_entry *i_get_exception_base(zend_object *object) /* {{{ */
85{
86 return instanceof_function(object->ce, zend_ce_exception) ? zend_ce_exception : zend_ce_error;
87}
88/* }}} */
89
91{
92 return i_get_exception_base(object);
93}
94/* }}} */
95
97{
98 zval *previous, *ancestor, *ex;
99 zval pv, zv, rv;
100 zend_class_entry *base_ce;
101
102 if (!exception || !add_previous) {
103 return;
104 }
105
106 if (exception == add_previous || zend_is_unwind_exit(add_previous) || zend_is_graceful_exit(add_previous)) {
107 OBJ_RELEASE(add_previous);
108 return;
109 }
110
111 ZEND_ASSERT(instanceof_function(add_previous->ce, zend_ce_throwable)
112 && "Previous exception must implement Throwable");
113
114 ZVAL_OBJ(&pv, add_previous);
116 ex = &zv;
117 do {
118 ancestor = zend_read_property_ex(i_get_exception_base(add_previous), add_previous, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
119 ZVAL_DEREF(ancestor);
120 while (Z_TYPE_P(ancestor) == IS_OBJECT) {
121 if (Z_OBJ_P(ancestor) == Z_OBJ_P(ex)) {
122 OBJ_RELEASE(add_previous);
123 return;
124 }
125 ancestor = zend_read_property_ex(i_get_exception_base(Z_OBJ_P(ancestor)), Z_OBJ_P(ancestor), ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
126 ZVAL_DEREF(ancestor);
127 }
128 base_ce = i_get_exception_base(Z_OBJ_P(ex));
129 previous = zend_read_property_ex(base_ce, Z_OBJ_P(ex), ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
130 ZVAL_DEREF(previous);
131 if (Z_TYPE_P(previous) == IS_NULL) {
132 zend_update_property_ex(base_ce, Z_OBJ_P(ex), ZSTR_KNOWN(ZEND_STR_PREVIOUS), &pv);
133 GC_DELREF(add_previous);
134 return;
135 }
136 ex = previous;
137 } while (Z_OBJ_P(ex) != add_previous);
138}
139/* }}} */
140
141void zend_exception_save(void) /* {{{ */
142{
143 if (EG(prev_exception)) {
144 zend_exception_set_previous(EG(exception), EG(prev_exception));
145 }
146 if (EG(exception)) {
147 EG(prev_exception) = EG(exception);
148 }
149 EG(exception) = NULL;
150}
151/* }}} */
152
153void zend_exception_restore(void) /* {{{ */
154{
155 if (EG(prev_exception)) {
156 if (EG(exception)) {
157 zend_exception_set_previous(EG(exception), EG(prev_exception));
158 } else {
159 EG(exception) = EG(prev_exception);
160 }
161 EG(prev_exception) = NULL;
162 }
163}
164/* }}} */
165
166static zend_always_inline bool is_handle_exception_set(void) {
167 zend_execute_data *execute_data = EG(current_execute_data);
168 return !execute_data
169 || !execute_data->func
170 || !ZEND_USER_CODE(execute_data->func->common.type)
171 || execute_data->opline->opcode == ZEND_HANDLE_EXCEPTION;
172}
173
175{
176#ifdef HAVE_DTRACE
177 if (DTRACE_EXCEPTION_THROWN_ENABLED()) {
178 if (exception != NULL) {
179 DTRACE_EXCEPTION_THROWN(ZSTR_VAL(exception->ce->name));
180 } else {
181 DTRACE_EXCEPTION_THROWN(NULL);
182 }
183 }
184#endif /* HAVE_DTRACE */
185
186 if (exception != NULL) {
187 zend_object *previous = EG(exception);
188 if (previous && zend_is_unwind_exit(previous)) {
189 /* Don't replace unwinding exception with different exception. */
191 return;
192 }
193
196 if (previous) {
197 return;
198 }
199 }
200 if (!EG(current_execute_data)) {
202 return;
203 }
204 if (EG(exception)) {
205 if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF
209 if (EG(exception)) {
211 }
212 return;
213 } else {
215 }
216 zend_bailout();
217 }
218 zend_error_noreturn(E_CORE_ERROR, "Exception thrown without a stack frame");
219 }
220
223 }
224
225 if (is_handle_exception_set()) {
226 /* no need to rethrow the exception */
227 return;
228 }
229 EG(opline_before_exception) = EG(current_execute_data)->opline;
230 EG(current_execute_data)->opline = EG(exception_op);
231}
232/* }}} */
233
234ZEND_API void zend_clear_exception(void) /* {{{ */
235{
237 if (EG(prev_exception)) {
238 OBJ_RELEASE(EG(prev_exception));
239 EG(prev_exception) = NULL;
240 }
241 if (!EG(exception)) {
242 return;
243 }
244 /* exception may have destructor */
246 EG(exception) = NULL;
248 if (EG(current_execute_data)) {
249 EG(current_execute_data)->opline = EG(opline_before_exception);
250 }
251#if ZEND_DEBUG
252 EG(opline_before_exception) = NULL;
253#endif
254}
255/* }}} */
256
257static zend_object *zend_default_exception_new(zend_class_entry *class_type) /* {{{ */
258{
259 zval tmp;
260 zval trace;
261 zend_class_entry *base_ce;
262 zend_string *filename;
263
264 zend_object *object = zend_objects_new(class_type);
265 object_properties_init(object, class_type);
266
267 if (EG(current_execute_data)) {
269 0,
270 EG(exception_ignore_args) ? DEBUG_BACKTRACE_IGNORE_ARGS : 0, 0);
271 } else {
272 array_init(&trace);
273 }
274 Z_SET_REFCOUNT(trace, 0);
275
276 base_ce = i_get_exception_base(object);
277
278 if (EXPECTED((class_type != zend_ce_parse_error && class_type != zend_ce_compile_error)
279 || !(filename = zend_get_compiled_filename()))) {
281 zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
282 zval_ptr_dtor(&tmp);
284 zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
285 } else {
286 ZVAL_STR(&tmp, filename);
287 zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
289 zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
290 }
291 zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_TRACE), &trace);
292
293 return object;
294}
295/* }}} */
296
297/* {{{ Clone the exception object */
299{
300 /* __clone() is private but this is reachable with reflection */
301 zend_throw_exception(NULL, "Cannot clone object using __clone()", 0);
302}
303/* }}} */
304
305/* {{{ Exception constructor */
307{
308 zend_string *message = NULL;
309 zend_long code = 0;
310 zval tmp, *object, *previous = NULL;
311 zend_class_entry *base_ce;
312
313 object = ZEND_THIS;
314 base_ce = i_get_exception_base(Z_OBJ_P(object));
315
316 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|SlO!", &message, &code, &previous, zend_ce_throwable) == FAILURE) {
318 }
319
320 if (message) {
321 ZVAL_STR(&tmp, message);
322 zend_update_property_ex(base_ce, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
323 }
324
325 if (code) {
326 ZVAL_LONG(&tmp, code);
327 zend_update_property_ex(base_ce, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_CODE), &tmp);
328 }
329
330 if (previous) {
331 zend_update_property_ex(base_ce, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous);
332 }
333}
334/* }}} */
335
336/* {{{ Exception unserialize checks */
337#define CHECK_EXC_TYPE(id, type) \
338 pvalue = zend_read_property_ex(i_get_exception_base(Z_OBJ_P(object)), Z_OBJ_P(object), ZSTR_KNOWN(id), 1, &value); \
339 if (Z_TYPE_P(pvalue) != IS_NULL && Z_TYPE_P(pvalue) != type) { \
340 zend_unset_property(i_get_exception_base(Z_OBJ_P(object)), Z_OBJ_P(object), ZSTR_VAL(ZSTR_KNOWN(id)), ZSTR_LEN(ZSTR_KNOWN(id))); \
341 }
342
344{
346
347 zval value, *pvalue;
348 zval *object = ZEND_THIS;
349 CHECK_EXC_TYPE(ZEND_STR_MESSAGE, IS_STRING);
350 CHECK_EXC_TYPE(ZEND_STR_CODE, IS_LONG);
351 /* The type of all other properties is enforced through typed properties. */
352}
353/* }}} */
354
355/* {{{ ErrorException constructor */
357{
358 zend_string *message = NULL, *filename = NULL;
359 zend_long code = 0, severity = E_ERROR, lineno;
360 bool lineno_is_null = 1;
361 zval tmp, *object, *previous = NULL;
362
363 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|SllS!l!O!", &message, &code, &severity, &filename, &lineno, &lineno_is_null, &previous, zend_ce_throwable) == FAILURE) {
365 }
366
367 object = ZEND_THIS;
368
369 if (message) {
370 ZVAL_STR_COPY(&tmp, message);
371 zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
372 zval_ptr_dtor(&tmp);
373 }
374
375 if (code) {
376 ZVAL_LONG(&tmp, code);
377 zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_CODE), &tmp);
378 }
379
380 if (previous) {
381 zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous);
382 }
383
384 ZVAL_LONG(&tmp, severity);
385 zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_SEVERITY), &tmp);
386
387 if (filename) {
388 ZVAL_STR_COPY(&tmp, filename);
389 zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
390 zval_ptr_dtor(&tmp);
391 }
392
393 if (!lineno_is_null) {
394 ZVAL_LONG(&tmp, lineno);
395 zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
396 } else if (filename) {
397 ZVAL_LONG(&tmp, 0);
398 zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
399 }
400}
401/* }}} */
402
403#define GET_PROPERTY(object, id) \
404 zend_read_property_ex(i_get_exception_base(Z_OBJ_P(object)), Z_OBJ_P(object), ZSTR_KNOWN(id), 0, &rv)
405#define GET_PROPERTY_SILENT(object, id) \
406 zend_read_property_ex(i_get_exception_base(Z_OBJ_P(object)), Z_OBJ_P(object), ZSTR_KNOWN(id), 1, &rv)
407
408/* {{{ Get the file in which the exception occurred */
410{
411 zval *prop, rv;
412
414
415 prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_FILE);
416 RETURN_STR(zval_get_string(prop));
417}
418/* }}} */
419
420/* {{{ Get the line in which the exception occurred */
422{
423 zval *prop, rv;
424
426
427 prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_LINE);
428 RETURN_LONG(zval_get_long(prop));
429}
430/* }}} */
431
432/* {{{ Get the exception message */
434{
435 zval *prop, rv;
436
438
439 prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_MESSAGE);
440 RETURN_STR(zval_get_string(prop));
441}
442/* }}} */
443
444/* {{{ Get the exception code */
446{
447 zval *prop, rv;
448
450
451 prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_CODE);
452 ZVAL_DEREF(prop);
453 ZVAL_COPY(return_value, prop);
454}
455/* }}} */
456
457/* {{{ Get the stack trace for the location in which the exception occurred */
459{
460 zval *prop, rv;
461
463
464 prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_TRACE);
465 ZVAL_DEREF(prop);
466 ZVAL_COPY(return_value, prop);
467}
468/* }}} */
469
470/* {{{ Get the exception severity */
472{
473 zval *prop, rv;
474
476
477 prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_SEVERITY);
478 ZVAL_DEREF(prop);
479 ZVAL_COPY(return_value, prop);
480}
481/* }}} */
482
483#define TRACE_APPEND_KEY(key) do { \
484 tmp = zend_hash_find(ht, key); \
485 if (tmp) { \
486 if (Z_TYPE_P(tmp) != IS_STRING) { \
487 zend_error(E_WARNING, "Value for %s is not a string", \
488 ZSTR_VAL(key)); \
489 smart_str_appends(str, "[unknown]"); \
490 } else { \
491 smart_str_appends(str, Z_STRVAL_P(tmp)); \
492 } \
493 } \
494 } while (0)
495
496static void _build_trace_args(zval *arg, smart_str *str) /* {{{ */
497{
498 /* the trivial way would be to do
499 * convert_to_string(arg);
500 * append it and kill the now tmp arg.
501 * but that could cause some E_NOTICE and also damn long lines.
502 */
503
505
506 if (smart_str_append_zval(str, arg, EG(exception_string_param_max_len)) == SUCCESS) {
507 smart_str_appends(str, ", ");
508 } else {
509 switch (Z_TYPE_P(arg)) {
510 case IS_RESOURCE:
511 smart_str_appends(str, "Resource id #");
512 smart_str_append_long(str, Z_RES_HANDLE_P(arg));
513 smart_str_appends(str, ", ");
514 break;
515 case IS_ARRAY:
516 smart_str_appends(str, "Array, ");
517 break;
518 case IS_OBJECT: {
519 zend_string *class_name = Z_OBJ_HANDLER_P(arg, get_class_name)(Z_OBJ_P(arg));
520 smart_str_appends(str, "Object(");
521 smart_str_appends(str, ZSTR_VAL(class_name));
522 smart_str_appends(str, "), ");
523 zend_string_release_ex(class_name, 0);
524 break;
525 }
526 }
527 }
528}
529/* }}} */
530
531static void _build_trace_string(smart_str *str, HashTable *ht, uint32_t num) /* {{{ */
532{
533 zval *file, *tmp;
534
535 smart_str_appendc(str, '#');
536 smart_str_append_long(str, num);
537 smart_str_appendc(str, ' ');
538
539 file = zend_hash_find_known_hash(ht, ZSTR_KNOWN(ZEND_STR_FILE));
540 if (file) {
541 if (Z_TYPE_P(file) != IS_STRING) {
542 zend_error(E_WARNING, "File name is not a string");
543 smart_str_appends(str, "[unknown file]: ");
544 } else{
545 zend_long line = 0;
546 tmp = zend_hash_find_known_hash(ht, ZSTR_KNOWN(ZEND_STR_LINE));
547 if (tmp) {
548 if (Z_TYPE_P(tmp) == IS_LONG) {
549 line = Z_LVAL_P(tmp);
550 } else {
551 zend_error(E_WARNING, "Line is not an int");
552 }
553 }
554 smart_str_append(str, Z_STR_P(file));
555 smart_str_appendc(str, '(');
556 smart_str_append_long(str, line);
557 smart_str_appends(str, "): ");
558 }
559 } else {
560 smart_str_appends(str, "[internal function]: ");
561 }
562 TRACE_APPEND_KEY(ZSTR_KNOWN(ZEND_STR_CLASS));
563 TRACE_APPEND_KEY(ZSTR_KNOWN(ZEND_STR_TYPE));
564 TRACE_APPEND_KEY(ZSTR_KNOWN(ZEND_STR_FUNCTION));
565 smart_str_appendc(str, '(');
566 tmp = zend_hash_find_known_hash(ht, ZSTR_KNOWN(ZEND_STR_ARGS));
567 if (tmp) {
568 if (Z_TYPE_P(tmp) == IS_ARRAY) {
569 size_t last_len = ZSTR_LEN(str->s);
571 zval *arg;
572
574 if (name) {
575 smart_str_append(str, name);
576 smart_str_appends(str, ": ");
577 }
578 _build_trace_args(arg, str);
580
581 if (last_len != ZSTR_LEN(str->s)) {
582 ZSTR_LEN(str->s) -= 2; /* remove last ', ' */
583 }
584 } else {
585 zend_error(E_WARNING, "args element is not an array");
586 }
587 }
588 smart_str_appends(str, ")\n");
589}
590/* }}} */
591
593 zend_ulong index;
594 zval *frame;
595 uint32_t num = 0;
596 smart_str str = {0};
597
598 ZEND_HASH_FOREACH_NUM_KEY_VAL(trace, index, frame) {
599 if (Z_TYPE_P(frame) != IS_ARRAY) {
600 zend_error(E_WARNING, "Expected array for frame " ZEND_ULONG_FMT, index);
601 continue;
602 }
603
604 _build_trace_string(&str, Z_ARRVAL_P(frame), num++);
606
607 if (include_main) {
608 smart_str_appendc(&str, '#');
609 smart_str_append_long(&str, num);
610 smart_str_appends(&str, " {main}");
611 }
612
613 smart_str_0(&str);
614 return str.s ? str.s : ZSTR_EMPTY_ALLOC();
615}
616
617/* {{{ Obtain the backtrace for the exception as a string (instead of an array) */
618ZEND_METHOD(Exception, getTraceAsString)
619{
620
622
623 zval *object = ZEND_THIS;
624 zend_class_entry *base_ce = i_get_exception_base(Z_OBJ_P(object));
625 zval rv;
626 zval *trace = zend_read_property_ex(base_ce, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_TRACE), 1, &rv);
627 if (EG(exception)) {
629 }
630
631 ZVAL_DEREF(trace);
632 /* Type should be guaranteed by property type. */
633 ZEND_ASSERT(Z_TYPE_P(trace) == IS_ARRAY);
634 RETURN_NEW_STR(zend_trace_to_string(Z_ARRVAL_P(trace), /* include_main */ true));
635}
636/* }}} */
637
638/* {{{ Return previous Throwable or NULL. */
640{
641 zval rv;
642
644
646} /* }}} */
647
648/* {{{ Obtain the string representation of the Exception object */
650{
651 zval trace, *exception;
652 zend_class_entry *base_ce;
653 zend_string *str;
654 zend_fcall_info fci;
655 zval rv, tmp;
656 zend_string *fname;
657
659
660 str = ZSTR_EMPTY_ALLOC();
661
663 fname = ZSTR_INIT_LITERAL("gettraceasstring", 0);
664
665 while (exception && Z_TYPE_P(exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception), zend_ce_throwable)) {
666 zend_string *prev_str = str;
667 zend_string *message = zval_get_string(GET_PROPERTY(exception, ZEND_STR_MESSAGE));
668 zend_string *file = zval_get_string(GET_PROPERTY(exception, ZEND_STR_FILE));
669 zend_long line = zval_get_long(GET_PROPERTY(exception, ZEND_STR_LINE));
670
671 fci.size = sizeof(fci);
672 ZVAL_STR(&fci.function_name, fname);
673 fci.object = Z_OBJ_P(exception);
674 fci.retval = &trace;
675 fci.param_count = 0;
676 fci.params = NULL;
677 fci.named_params = NULL;
678
680
681 if (Z_TYPE(trace) != IS_STRING) {
682 zval_ptr_dtor(&trace);
683 ZVAL_UNDEF(&trace);
684 }
685
687 zend_string *real_message = zend_strpprintf_unchecked(0, "%S and defined", message);
688 zend_string_release_ex(message, 0);
689 message = real_message;
690 }
691
692 zend_string *tmp_trace = (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace))
693 ? zend_string_copy(Z_STR(trace))
694 : ZSTR_INIT_LITERAL("#0 {main}\n", false);
695
697
698 if (ZSTR_LEN(message) > 0) {
699 zval message_zv;
700 ZVAL_STR(&message_zv, message);
701
702 str = zend_strpprintf_unchecked(0, "%S: %S in %S:" ZEND_LONG_FMT "\nStack trace:\n%S%s%S",
703 name, message, file, line,
704 tmp_trace, ZSTR_LEN(prev_str) ? "\n\nNext " : "", prev_str);
705 } else {
706 str = zend_strpprintf_unchecked(0, "%S in %S:" ZEND_LONG_FMT "\nStack trace:\n%S%s%S",
707 name, file, line,
708 tmp_trace, ZSTR_LEN(prev_str) ? "\n\nNext " : "", prev_str);
709 }
710 zend_string_release_ex(tmp_trace, false);
711
712 zend_string_release_ex(prev_str, 0);
713 zend_string_release_ex(message, 0);
715 zval_ptr_dtor(&trace);
716
718 exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS);
721 break;
722 }
723 }
724 zend_string_release_ex(fname, 0);
725
727 /* Reset apply counts */
728 while (Z_TYPE_P(exception) == IS_OBJECT && (base_ce = i_get_exception_base(Z_OBJ_P(exception))) && instanceof_function(Z_OBJCE_P(exception), base_ce)) {
731 } else {
732 break;
733 }
734 exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS);
736 }
737
739 base_ce = i_get_exception_base(Z_OBJ_P(exception));
740
741 /* We store the result in the private property string so we can access
742 * the result in uncaught exception handlers without memleaks. */
743 ZVAL_STR(&tmp, str);
744 zend_update_property_ex(base_ce, Z_OBJ_P(exception), ZSTR_KNOWN(ZEND_STR_STRING), &tmp);
745
746 RETURN_STR(str);
747}
748/* }}} */
749
750static void zend_init_exception_class_entry(zend_class_entry *ce) {
751 ce->create_object = zend_default_exception_new;
752 ce->default_object_handlers = &default_exception_handlers;
753}
754
756{
757 zend_ce_throwable = register_class_Throwable(zend_ce_stringable);
758 zend_ce_throwable->interface_gets_implemented = zend_implement_throwable;
759
760 memcpy(&default_exception_handlers, &std_object_handlers, sizeof(zend_object_handlers));
761 default_exception_handlers.clone_obj = NULL;
762
763 zend_ce_exception = register_class_Exception(zend_ce_throwable);
764 zend_init_exception_class_entry(zend_ce_exception);
765
766 zend_ce_error_exception = register_class_ErrorException(zend_ce_exception);
767 zend_init_exception_class_entry(zend_ce_error_exception);
768
769 zend_ce_error = register_class_Error(zend_ce_throwable);
770 zend_init_exception_class_entry(zend_ce_error);
771
772 zend_ce_compile_error = register_class_CompileError(zend_ce_error);
773 zend_init_exception_class_entry(zend_ce_compile_error);
774
775 zend_ce_parse_error = register_class_ParseError(zend_ce_compile_error);
776 zend_init_exception_class_entry(zend_ce_parse_error);
777
778 zend_ce_type_error = register_class_TypeError(zend_ce_error);
779 zend_init_exception_class_entry(zend_ce_type_error);
780
781 zend_ce_argument_count_error = register_class_ArgumentCountError(zend_ce_type_error);
782 zend_init_exception_class_entry(zend_ce_argument_count_error);
783
784 zend_ce_value_error = register_class_ValueError(zend_ce_error);
785 zend_init_exception_class_entry(zend_ce_value_error);
786
787 zend_ce_arithmetic_error = register_class_ArithmeticError(zend_ce_error);
788 zend_init_exception_class_entry(zend_ce_arithmetic_error);
789
790 zend_ce_division_by_zero_error = register_class_DivisionByZeroError(zend_ce_arithmetic_error);
791 zend_init_exception_class_entry(zend_ce_division_by_zero_error);
792
793 zend_ce_unhandled_match_error = register_class_UnhandledMatchError(zend_ce_error);
794 zend_init_exception_class_entry(zend_ce_unhandled_match_error);
795
796 zend_ce_request_parse_body_exception = register_class_RequestParseBodyException(zend_ce_exception);
797 zend_init_exception_class_entry(zend_ce_request_parse_body_exception);
798
799 INIT_CLASS_ENTRY(zend_ce_unwind_exit, "UnwindExit", NULL);
800
801 INIT_CLASS_ENTRY(zend_ce_graceful_exit, "GracefulExit", NULL);
802}
803/* }}} */
804
805/* {{{ Deprecated - Use zend_ce_exception directly instead */
810/* }}} */
811
812/* {{{ Deprecated - Use zend_ce_error_exception directly instead */
817/* }}} */
818
819static zend_object *zend_throw_exception_zstr(zend_class_entry *exception_ce, zend_string *message, zend_long code) /* {{{ */
820{
821 zval ex, tmp;
822
823 if (!exception_ce) {
824 exception_ce = zend_ce_exception;
825 }
826
827 ZEND_ASSERT(instanceof_function(exception_ce, zend_ce_throwable)
828 && "Exceptions must implement Throwable");
829
830 object_init_ex(&ex, exception_ce);
831
832 if (message) {
833 ZVAL_STR(&tmp, message);
834 zend_update_property_ex(exception_ce, Z_OBJ(ex), ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
835 }
836 if (code) {
837 ZVAL_LONG(&tmp, code);
838 zend_update_property_ex(exception_ce, Z_OBJ(ex), ZSTR_KNOWN(ZEND_STR_CODE), &tmp);
839 }
840
842
843 return Z_OBJ(ex);
844}
845/* }}} */
846
847ZEND_API ZEND_COLD zend_object *zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code) /* {{{ */
848{
849 zend_string *msg_str = message ? zend_string_init(message, strlen(message), 0) : NULL;
850 zend_object *ex = zend_throw_exception_zstr(exception_ce, msg_str, code);
851 if (msg_str) {
852 zend_string_release(msg_str);
853 }
854 return ex;
855}
856/* }}} */
857
858ZEND_API ZEND_COLD zend_object *zend_throw_exception_ex(zend_class_entry *exception_ce, zend_long code, const char *format, ...) /* {{{ */
859{
860 va_list arg;
861 char *message;
862 zend_object *obj;
863
864 va_start(arg, format);
865 zend_vspprintf(&message, 0, format, arg);
866 va_end(arg);
867 obj = zend_throw_exception(exception_ce, message, code);
868 efree(message);
869 return obj;
870}
871/* }}} */
872
874{
875 zend_object *obj = zend_throw_exception_zstr(exception_ce, message, code);
876 if (exception_ce && instanceof_function(exception_ce, zend_ce_error_exception)) {
877 zval tmp;
878 ZVAL_LONG(&tmp, severity);
879 zend_update_property_ex(zend_ce_error_exception, obj, ZSTR_KNOWN(ZEND_STR_SEVERITY), &tmp);
880 }
881 return obj;
882}
883/* }}} */
884
885static void zend_error_va(int type, zend_string *file, uint32_t lineno, const char *format, ...) /* {{{ */
886{
887 va_list args;
888 va_start(args, format);
889 zend_string *message = zend_vstrpprintf(0, format, args);
890 zend_observer_error_notify(type, file, lineno, message);
891 zend_error_cb(type, file, lineno, message);
892 zend_string_release(message);
893 va_end(args);
894}
895/* }}} */
896
897/* This function doesn't return if it uses E_ERROR */
899{
901 zend_class_entry *ce_exception;
903
905 ce_exception = ex->ce;
906 EG(exception) = NULL;
907 if (ce_exception == zend_ce_parse_error || ce_exception == zend_ce_compile_error) {
908 zend_string *message = zval_get_string(GET_PROPERTY(&exception, ZEND_STR_MESSAGE));
909 zend_string *file = zval_get_string(GET_PROPERTY_SILENT(&exception, ZEND_STR_FILE));
910 zend_long line = zval_get_long(GET_PROPERTY_SILENT(&exception, ZEND_STR_LINE));
911 int type = (ce_exception == zend_ce_parse_error ? E_PARSE : E_COMPILE_ERROR) | E_DONT_BAIL;
912
913 zend_observer_error_notify(type, file, line, message);
914 zend_error_cb(type, file, line, message);
915
917 zend_string_release_ex(message, 0);
918 } else if (instanceof_function(ce_exception, zend_ce_throwable)) {
919 zval tmp;
920 zend_string *str, *file = NULL;
921 zend_long line = 0;
922
923 zend_call_known_instance_method_with_0_params(ex->ce->__tostring, ex, &tmp);
924 if (!EG(exception)) {
925 if (Z_TYPE(tmp) != IS_STRING) {
926 zend_error(E_WARNING, "%s::__toString() must return a string", ZSTR_VAL(ce_exception->name));
927 } else {
928 zend_update_property_ex(i_get_exception_base(ex), ex, ZSTR_KNOWN(ZEND_STR_STRING), &tmp);
929 }
930 }
931 zval_ptr_dtor(&tmp);
932
933 if (EG(exception)) {
934 zval zv;
935
937 /* do the best we can to inform about the inner exception */
938 if (instanceof_function(ce_exception, zend_ce_exception) || instanceof_function(ce_exception, zend_ce_error)) {
939 file = zval_get_string(GET_PROPERTY_SILENT(&zv, ZEND_STR_FILE));
940 line = zval_get_long(GET_PROPERTY_SILENT(&zv, ZEND_STR_LINE));
941 }
942
943 zend_error_va(E_WARNING, (file && ZSTR_LEN(file) > 0) ? file : NULL, line,
944 "Uncaught %s in exception handling during call to %s::__toString()",
945 ZSTR_VAL(Z_OBJCE(zv)->name), ZSTR_VAL(ce_exception->name));
946
947 if (file) {
949 }
950 }
951
952 str = zval_get_string(GET_PROPERTY_SILENT(&exception, ZEND_STR_STRING));
953 file = zval_get_string(GET_PROPERTY_SILENT(&exception, ZEND_STR_FILE));
954 line = zval_get_long(GET_PROPERTY_SILENT(&exception, ZEND_STR_LINE));
955
956 zend_error_va(severity | E_DONT_BAIL,
957 (file && ZSTR_LEN(file) > 0) ? file : NULL, line,
958 "Uncaught %S\n thrown", str);
959
962 } else if (ce_exception == &zend_ce_unwind_exit || ce_exception == &zend_ce_graceful_exit) {
963 /* We successfully unwound, nothing more to do.
964 * We still return FAILURE in this case, as further execution should still be aborted. */
965 } else {
966 zend_error(severity, "Uncaught exception %s", ZSTR_VAL(ce_exception->name));
967 }
968
970 return result;
971}
972/* }}} */
973
974ZEND_NORETURN void zend_exception_uncaught_error(const char *format, ...) {
975 va_list va;
976 va_start(va, format);
977 zend_string *prefix = zend_vstrpprintf(0, format, va);
978 va_end(va);
979
981 zval exception_zv;
982 ZVAL_OBJ_COPY(&exception_zv, EG(exception));
984
985 zend_string *exception_str = zval_get_string(&exception_zv);
987 "%s: Uncaught %s", ZSTR_VAL(prefix), ZSTR_VAL(exception_str));
988}
989
991{
992 if (exception == NULL || Z_TYPE_P(exception) != IS_OBJECT) {
993 zend_error_noreturn(E_CORE_ERROR, "Need to supply an object when throwing an exception");
994 }
995
996 zend_class_entry *exception_ce = Z_OBJCE_P(exception);
997
998 if (!exception_ce || !instanceof_function(exception_ce, zend_ce_throwable)) {
999 zend_throw_error(NULL, "Cannot throw objects that do not implement Throwable");
1001 return;
1002 }
1003
1005}
1006/* }}} */
1007
1009{
1010 return zend_objects_new(&zend_ce_unwind_exit);
1011}
1012
1014{
1015 return zend_objects_new(&zend_ce_graceful_exit);
1016}
1017
1019{
1022 EG(opline_before_exception) = EG(current_execute_data)->opline;
1023 EG(current_execute_data)->opline = EG(exception_op);
1024}
1025
1027{
1030 EG(opline_before_exception) = EG(current_execute_data)->opline;
1031 EG(current_execute_data)->opline = EG(exception_op);
1032}
1033
1035{
1036 return ex->ce == &zend_ce_unwind_exit;
1037}
1038
1040{
1041 return ex->ce == &zend_ce_graceful_exit;
1042}
bool exception
Definition assert.c:30
file(string $filename, int $flags=0, $context=null)
strstr(string $haystack, string $needle, bool $before_needle=false)
zend_ffi_type * type
Definition ffi.c:3812
zval * zv
Definition ffi.c:3975
memcpy(ptr1, ptr2, size)
zval * arg
Definition ffi.c:3975
HashTable * ht
Definition ffi.c:4838
#define NULL
Definition gdcache.h:45
#define prefix
#define SUCCESS
Definition hash_sha3.c:261
#define pvalue(o)
Definition minilua.c:245
int line
Definition php_ffi.h:54
phpdbg_frame_t frame
Definition phpdbg.h:236
zend_object * ex
zval rv
Definition session.c:1024
zend_object *(* create_object)(zend_class_entry *class_type)
Definition zend.h:195
zend_string * name
Definition zend.h:149
uint32_t ce_flags
Definition zend.h:156
zend_class_entry * parent
Definition zend.h:152
const zend_object_handlers * default_object_handlers
Definition zend.h:186
HashTable * named_params
Definition zend_API.h:56
uint32_t param_count
Definition zend_API.h:51
zend_object * object
Definition zend_API.h:50
zend_class_entry * ce
Definition zend_types.h:560
zend_string * s
ZEND_API zend_string * zend_vstrpprintf(size_t max_len, const char *format, va_list ap)
Definition zend.c:335
ZEND_API void(* zend_error_cb)(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message)
Definition zend.c:90
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format,...)
Definition zend.c:1703
ZEND_API zend_string * zend_strpprintf_unchecked(size_t max_len, const char *format,...)
Definition zend.c:365
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API ZEND_COLD void zend_error(int type, const char *format,...)
Definition zend.c:1666
ZEND_API ZEND_COLD void zend_user_exception_handler(void)
Definition zend.c:1887
ZEND_API size_t zend_vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap)
Definition zend.c:283
#define DEBUG_BACKTRACE_IGNORE_ARGS
Definition zend.h:451
#define zend_bailout()
Definition zend.h:268
ZEND_API zval * zend_read_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, bool silent, zval *rv)
Definition zend_API.c:5187
ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type)
Definition zend_API.c:1849
ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec,...)
Definition zend_API.c:1300
ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type)
Definition zend_API.c:1688
ZEND_API void zend_update_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, zval *value)
Definition zend_API.c:4979
#define ZEND_NUM_ARGS()
Definition zend_API.h:530
#define ZEND_PARSE_PARAMETERS_NONE()
Definition zend_API.h:1623
#define ZVAL_STRING(z, s)
Definition zend_API.h:956
#define INIT_CLASS_ENTRY(class_container, class_name, functions)
Definition zend_API.h:279
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_NEW_STR(s)
Definition zend_API.h:1041
struct _zend_fcall_info zend_fcall_info
#define ZEND_METHOD(classname, name)
Definition zend_API.h:76
#define RETURN_THROWS()
Definition zend_API.h:1060
#define RETURN_STR(s)
Definition zend_API.h:1039
#define ZEND_THIS
Definition zend_API.h:523
ZEND_API zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
#define array_init(arg)
Definition zend_API.h:537
#define efree(ptr)
Definition zend_alloc.h:155
ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int options, int limit)
struct _zval_struct zval
strlen(string $string)
zend_string_release_ex(func->internal_function.function_name, 0)
zval * args
ZEND_API int zend_get_compiled_lineno(void)
ZEND_API zend_string * zend_get_compiled_filename(void)
#define ZEND_ACC_ENUM
#define ZEND_USER_CODE(type)
#define ZEND_API
#define E_COMPILE_ERROR
Definition zend_errors.h:29
#define E_PARSE
Definition zend_errors.h:25
#define E_ERROR
Definition zend_errors.h:23
#define E_WARNING
Definition zend_errors.h:24
#define E_CORE_ERROR
Definition zend_errors.h:27
#define E_DONT_BAIL
Definition zend_errors.h:41
ZEND_API zend_class_entry * zend_ce_arithmetic_error
ZEND_API ZEND_COLD zend_object * zend_throw_error_exception(zend_class_entry *exception_ce, zend_string *message, zend_long code, int severity)
ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception)
void zend_exception_restore(void)
ZEND_API zend_class_entry * zend_exception_get_default(void)
ZEND_API bool zend_is_unwind_exit(const zend_object *ex)
ZEND_API zend_string * zend_trace_to_string(HashTable *trace, bool include_main)
void zend_register_default_exception(void)
ZEND_API zend_class_entry * zend_ce_exception
ZEND_API ZEND_COLD void zend_throw_exception_object(zval *exception)
ZEND_API zend_class_entry * zend_ce_value_error
void zend_exception_save(void)
ZEND_API zend_class_entry * zend_ce_type_error
ZEND_API zend_class_entry * zend_ce_error_exception
ZEND_API zend_class_entry * zend_ce_compile_error
ZEND_API ZEND_COLD zend_object * zend_create_unwind_exit(void)
ZEND_API zend_class_entry * zend_ce_unhandled_match_error
#define GET_PROPERTY(object, id)
#define GET_PROPERTY_SILENT(object, id)
ZEND_API bool zend_is_graceful_exit(const zend_object *ex)
ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *ex, int severity)
ZEND_API ZEND_COLD zend_object * zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code)
#define TRACE_APPEND_KEY(key)
#define CHECK_EXC_TYPE(id, type)
ZEND_API ZEND_COLD void zend_throw_graceful_exit(void)
ZEND_API ZEND_COLD zend_object * zend_create_graceful_exit(void)
ZEND_API void(* zend_throw_exception_hook)(zend_object *ex)
ZEND_API zend_class_entry * zend_ce_division_by_zero_error
ZEND_NORETURN void zend_exception_uncaught_error(const char *format,...)
ZEND_API ZEND_COLD void zend_throw_unwind_exit(void)
ZEND_API zend_class_entry * zend_ce_request_parse_body_exception
ZEND_API zend_class_entry * zend_ce_parse_error
ZEND_API zend_class_entry * zend_ce_argument_count_error
ZEND_API void zend_clear_exception(void)
ZEND_API ZEND_COLD zend_object * zend_throw_exception_ex(zend_class_entry *exception_ce, zend_long code, const char *format,...)
ZEND_API zend_class_entry * zend_ce_throwable
ZEND_API zend_class_entry * zend_get_error_exception(void)
void zend_exception_set_previous(zend_object *exception, zend_object *add_previous)
ZEND_API zend_class_entry * zend_get_exception_base(zend_object *object)
ZEND_API zend_class_entry * zend_ce_error
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
ZEND_API uint32_t zend_get_executed_lineno(void)
ZEND_API const char * zend_get_executed_filename(void)
#define EG(v)
ZEND_API zval *ZEND_FASTCALL zend_hash_find_known_hash(const HashTable *ht, const zend_string *key)
Definition zend_hash.c:2679
#define ZEND_HASH_FOREACH_NUM_KEY_VAL(ht, _h, _val)
Definition zend_hash.h:1156
#define ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val)
Definition zend_hash.h:1166
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
ZEND_API zend_class_entry * zend_ce_stringable
#define ZEND_ULONG_FMT
Definition zend_long.h:88
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_LONG_FMT
Definition zend_long.h:87
struct _zend_string zend_string
ZEND_API const zend_object_handlers std_object_handlers
ZEND_API zend_object *ZEND_FASTCALL zend_objects_new(zend_class_entry *ce)
#define OBJ_RELEASE(obj)
#define EXPECTED(condition)
#define zend_always_inline
#define ZEND_ASSERT(c)
#define ZEND_COLD
#define ZEND_NORETURN
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
ZEND_API zend_result ZEND_FASTCALL smart_str_append_zval(smart_str *dest, const zval *value, size_t truncate)
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_INIT_LITERAL(s, persistent)
#define ZSTR_KNOWN(idx)
#define zend_string_equals_literal(str, literal)
#define ZSTR_EMPTY_ALLOC()
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_OBJ_HANDLER_P(zv_p, hf)
Definition zend_types.h:996
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define ZVAL_STR(z, s)
#define ZVAL_UNDEF(z)
#define IS_UNDEF
Definition zend_types.h:600
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define ZVAL_DEREF(z)
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
#define ZVAL_STR_COPY(z, s)
struct _zend_array HashTable
Definition zend_types.h:386
#define IS_RESOURCE
Definition zend_types.h:609
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define IS_ARRAY
Definition zend_types.h:607
#define ZVAL_COPY_DEREF(z, v)
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define Z_STR(zval)
Definition zend_types.h:971
#define GC_DELREF(p)
Definition zend_types.h:710
#define Z_UNPROTECT_RECURSION_P(zv)
Definition zend_types.h:889
#define IS_NULL
Definition zend_types.h:601
#define Z_OBJCE_P(zval_p)
#define ZVAL_OBJ(z, o)
@ FAILURE
Definition zend_types.h:61
#define Z_STRLEN(zval)
Definition zend_types.h:977
#define IS_OBJECT
Definition zend_types.h:608
#define IS_LONG
Definition zend_types.h:604
#define Z_RES_HANDLE_P(zval_p)
#define ZVAL_COPY(z, v)
#define ZVAL_OBJ_COPY(z, o)
#define Z_PROTECT_RECURSION_P(zv)
Definition zend_types.h:888
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define Z_TYPE(zval)
Definition zend_types.h:659
#define Z_SET_REFCOUNT(z, rc)
struct _zend_execute_data zend_execute_data
Definition zend_types.h:91
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define Z_IS_RECURSIVE_P(zv)
Definition zend_types.h:887
#define Z_OBJCE(zval)
#define Z_OBJ(zval)
Definition zend_types.h:989
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zval * return_value
zend_string * name
bool result
execute_data
object
value
#define ZEND_HANDLE_EXCEPTION