Coverage Report

Created: 2022-07-02 04:24

/src/php-src/Zend/zend_exceptions.c
Line
Count
Source (jump to first uncovered line)
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"
24
#include "zend_builtin_functions.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"
30
#include "zend_exceptions_arginfo.h"
31
32
ZEND_API zend_class_entry *zend_ce_throwable;
33
ZEND_API zend_class_entry *zend_ce_exception;
34
ZEND_API zend_class_entry *zend_ce_error_exception;
35
ZEND_API zend_class_entry *zend_ce_error;
36
ZEND_API zend_class_entry *zend_ce_compile_error;
37
ZEND_API zend_class_entry *zend_ce_parse_error;
38
ZEND_API zend_class_entry *zend_ce_type_error;
39
ZEND_API zend_class_entry *zend_ce_argument_count_error;
40
ZEND_API zend_class_entry *zend_ce_value_error;
41
ZEND_API zend_class_entry *zend_ce_arithmetic_error;
42
ZEND_API zend_class_entry *zend_ce_division_by_zero_error;
43
44
/* Internal pseudo-exception that is not exposed to userland. */
45
static zend_class_entry zend_ce_unwind_exit;
46
47
ZEND_API void (*zend_throw_exception_hook)(zval *ex);
48
49
static zend_object_handlers default_exception_handlers;
50
51
/* {{{ zend_implement_throwable */
52
static int zend_implement_throwable(zend_class_entry *interface, zend_class_entry *class_type)
53
100k
{
54
100k
  if (instanceof_function(class_type, zend_ce_exception) || instanceof_function(class_type, zend_ce_error)) {
55
100k
    return SUCCESS;
56
100k
  }
57
0
  zend_error_noreturn(E_ERROR, "Class %s cannot implement interface %s, extend %s or %s instead",
58
0
    ZSTR_VAL(class_type->name),
59
0
    ZSTR_VAL(interface->name),
60
0
    ZSTR_VAL(zend_ce_exception->name),
61
0
    ZSTR_VAL(zend_ce_error->name));
62
0
  return FAILURE;
63
0
}
64
/* }}} */
65
66
static inline zend_class_entry *i_get_exception_base(zval *object) /* {{{ */
67
1.55M
{
68
1.55M
  return instanceof_function(Z_OBJCE_P(object), zend_ce_exception) ? zend_ce_exception : zend_ce_error;
69
1.55M
}
70
/* }}} */
71
72
ZEND_API zend_class_entry *zend_get_exception_base(zval *object) /* {{{ */
73
0
{
74
0
  return i_get_exception_base(object);
75
0
}
76
/* }}} */
77
78
void zend_exception_set_previous(zend_object *exception, zend_object *add_previous) /* {{{ */
79
1.55M
{
80
1.55M
    zval *previous, *ancestor, *ex;
81
1.55M
  zval  pv, zv, rv;
82
1.55M
  zend_class_entry *base_ce;
83
84
1.55M
  if (!exception || !add_previous) {
85
1.55M
    return;
86
1.55M
  }
87
88
0
  if (exception == add_previous || zend_is_unwind_exit(add_previous)) {
89
0
    OBJ_RELEASE(add_previous);
90
0
    return;
91
0
  }
92
93
0
  ZVAL_OBJ(&pv, add_previous);
94
0
  if (!instanceof_function(Z_OBJCE(pv), zend_ce_throwable)) {
95
0
    zend_error_noreturn(E_CORE_ERROR, "Previous exception must implement Throwable");
96
0
    return;
97
0
  }
98
0
  ZVAL_OBJ(&zv, exception);
99
0
  ex = &zv;
100
0
  do {
101
0
    ancestor = zend_read_property_ex(i_get_exception_base(&pv), &pv, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
102
0
    while (Z_TYPE_P(ancestor) == IS_OBJECT) {
103
0
      if (Z_OBJ_P(ancestor) == Z_OBJ_P(ex)) {
104
0
        OBJ_RELEASE(add_previous);
105
0
        return;
106
0
      }
107
0
      ancestor = zend_read_property_ex(i_get_exception_base(ancestor), ancestor, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
108
0
    }
109
0
    base_ce = i_get_exception_base(ex);
110
0
    previous = zend_read_property_ex(base_ce, ex, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
111
0
    if (Z_TYPE_P(previous) == IS_NULL) {
112
0
      zend_update_property_ex(base_ce, ex, ZSTR_KNOWN(ZEND_STR_PREVIOUS), &pv);
113
0
      GC_DELREF(add_previous);
114
0
      return;
115
0
    }
116
0
    ex = previous;
117
0
  } while (Z_OBJ_P(ex) != add_previous);
118
0
}
119
/* }}} */
120
121
void zend_exception_save(void) /* {{{ */
122
1.41M
{
123
1.41M
  if (EG(prev_exception)) {
124
0
    zend_exception_set_previous(EG(exception), EG(prev_exception));
125
0
  }
126
1.41M
  if (EG(exception)) {
127
0
    EG(prev_exception) = EG(exception);
128
0
  }
129
1.41M
  EG(exception) = NULL;
130
1.41M
}
131
/* }}} */
132
133
void zend_exception_restore(void) /* {{{ */
134
1.41M
{
135
1.41M
  if (EG(prev_exception)) {
136
0
    if (EG(exception)) {
137
0
      zend_exception_set_previous(EG(exception), EG(prev_exception));
138
0
    } else {
139
0
      EG(exception) = EG(prev_exception);
140
0
    }
141
0
    EG(prev_exception) = NULL;
142
0
  }
143
1.41M
}
144
/* }}} */
145
146
ZEND_API ZEND_COLD void zend_throw_exception_internal(zval *exception) /* {{{ */
147
1.55M
{
148
#ifdef HAVE_DTRACE
149
  if (DTRACE_EXCEPTION_THROWN_ENABLED()) {
150
    if (exception != NULL) {
151
      DTRACE_EXCEPTION_THROWN(ZSTR_VAL(Z_OBJ_P(exception)->ce->name));
152
    } else {
153
      DTRACE_EXCEPTION_THROWN(NULL);
154
    }
155
  }
156
#endif /* HAVE_DTRACE */
157
158
1.55M
  if (exception != NULL) {
159
1.55M
    zend_object *previous = EG(exception);
160
1.55M
    zend_exception_set_previous(Z_OBJ_P(exception), EG(exception));
161
1.55M
    EG(exception) = Z_OBJ_P(exception);
162
1.55M
    if (previous) {
163
0
      return;
164
0
    }
165
1.55M
  }
166
1.55M
  if (!EG(current_execute_data)) {
167
1.55M
    if (exception && (Z_OBJCE_P(exception) == zend_ce_parse_error || Z_OBJCE_P(exception) == zend_ce_compile_error)) {
168
1.55M
      return;
169
1.55M
    }
170
128
    if (EG(exception)) {
171
128
      zend_exception_error(EG(exception), E_ERROR);
172
128
      zend_bailout();
173
128
    }
174
0
    zend_error_noreturn(E_CORE_ERROR, "Exception thrown without a stack frame");
175
0
  }
176
177
0
  if (zend_throw_exception_hook) {
178
0
    zend_throw_exception_hook(exception);
179
0
  }
180
181
0
  if (!EG(current_execute_data)->func ||
182
0
      !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
183
0
      EG(current_execute_data)->opline->opcode == ZEND_HANDLE_EXCEPTION) {
184
    /* no need to rethrow the exception */
185
0
    return;
186
0
  }
187
0
  EG(opline_before_exception) = EG(current_execute_data)->opline;
188
0
  EG(current_execute_data)->opline = EG(exception_op);
189
0
}
190
/* }}} */
191
192
ZEND_API void zend_clear_exception(void) /* {{{ */
193
1.40M
{
194
1.40M
  zend_object *exception;
195
1.40M
  if (EG(prev_exception)) {
196
0
    OBJ_RELEASE(EG(prev_exception));
197
0
    EG(prev_exception) = NULL;
198
0
  }
199
1.40M
  if (!EG(exception)) {
200
0
    return;
201
0
  }
202
  /* exception may have destructor */
203
1.40M
  exception = EG(exception);
204
1.40M
  EG(exception) = NULL;
205
1.40M
  OBJ_RELEASE(exception);
206
1.40M
  if (EG(current_execute_data)) {
207
0
    EG(current_execute_data)->opline = EG(opline_before_exception);
208
0
  }
209
#if ZEND_DEBUG
210
  EG(opline_before_exception) = NULL;
211
#endif
212
1.40M
}
213
/* }}} */
214
215
static zend_object *zend_default_exception_new_ex(zend_class_entry *class_type, int skip_top_traces) /* {{{ */
216
1.55M
{
217
1.55M
  zval obj, tmp;
218
1.55M
  zend_object *object;
219
1.55M
  zval trace;
220
1.55M
  zend_class_entry *base_ce;
221
1.55M
  zend_string *filename;
222
223
1.55M
  Z_OBJ(obj) = object = zend_objects_new(class_type);
224
1.55M
  Z_OBJ_HT(obj) = &default_exception_handlers;
225
226
1.55M
  object_properties_init(object, class_type);
227
228
1.55M
  if (EG(current_execute_data)) {
229
0
    zend_fetch_debug_backtrace(&trace,
230
0
      skip_top_traces,
231
0
      EG(exception_ignore_args) ? DEBUG_BACKTRACE_IGNORE_ARGS : 0, 0);
232
1.55M
  } else {
233
1.55M
    array_init(&trace);
234
1.55M
  }
235
1.55M
  Z_SET_REFCOUNT(trace, 0);
236
237
1.55M
  base_ce = i_get_exception_base(&obj);
238
239
1.55M
  if (EXPECTED((class_type != zend_ce_parse_error && class_type != zend_ce_compile_error)
240
128
      || !(filename = zend_get_compiled_filename()))) {
241
128
    ZVAL_STRING(&tmp, zend_get_executed_filename());
242
128
    zend_update_property_ex(base_ce, &obj, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
243
128
    zval_ptr_dtor(&tmp);
244
128
    ZVAL_LONG(&tmp, zend_get_executed_lineno());
245
128
    zend_update_property_ex(base_ce, &obj, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
246
1.55M
  } else {
247
1.55M
    ZVAL_STR(&tmp, filename);
248
1.55M
    zend_update_property_ex(base_ce, &obj, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
249
1.55M
    ZVAL_LONG(&tmp, zend_get_compiled_lineno());
250
1.55M
    zend_update_property_ex(base_ce, &obj, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
251
1.55M
  }
252
1.55M
  zend_update_property_ex(base_ce, &obj, ZSTR_KNOWN(ZEND_STR_TRACE), &trace);
253
254
1.55M
  return object;
255
1.55M
}
256
/* }}} */
257
258
static zend_object *zend_default_exception_new(zend_class_entry *class_type) /* {{{ */
259
1.55M
{
260
1.55M
  return zend_default_exception_new_ex(class_type, 0);
261
1.55M
}
262
/* }}} */
263
264
static zend_object *zend_error_exception_new(zend_class_entry *class_type) /* {{{ */
265
0
{
266
0
  return zend_default_exception_new_ex(class_type, 2);
267
0
}
268
/* }}} */
269
270
/* {{{ proto Exception|Error Exception|Error::__clone()
271
   Clone the exception object */
272
ZEND_COLD ZEND_METHOD(Exception, __clone)
273
0
{
274
  /* Should never be executable */
275
0
  zend_throw_exception(NULL, "Cannot clone object using __clone()", 0);
276
0
}
277
/* }}} */
278
279
/* {{{ proto Exception|Error::__construct(string message, int code [, Throwable previous])
280
   Exception constructor */
281
ZEND_METHOD(Exception, __construct)
282
0
{
283
0
  zend_string *message = NULL;
284
0
  zend_long   code = 0;
285
0
  zval  tmp, *object, *previous = NULL;
286
0
  zend_class_entry *base_ce;
287
288
0
  object = ZEND_THIS;
289
0
  base_ce = i_get_exception_base(object);
290
291
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|SlO!", &message, &code, &previous, zend_ce_throwable) == FAILURE) {
292
0
    RETURN_THROWS();
293
0
  }
294
295
0
  if (message) {
296
0
    ZVAL_STR(&tmp, message);
297
0
    zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
298
0
  }
299
300
0
  if (code) {
301
0
    ZVAL_LONG(&tmp, code);
302
0
    zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_CODE), &tmp);
303
0
  }
304
305
0
  if (previous) {
306
0
    zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous);
307
0
  }
308
0
}
309
/* }}} */
310
311
/* {{{ proto Exception::__wakeup()
312
   Exception unserialize checks */
313
#define CHECK_EXC_TYPE(id, type) \
314
0
  pvalue = zend_read_property_ex(i_get_exception_base(object), (object), ZSTR_KNOWN(id), 1, &value); \
315
0
  if (Z_TYPE_P(pvalue) != IS_NULL && Z_TYPE_P(pvalue) != type) { \
316
0
    zend_unset_property(i_get_exception_base(object), object, ZSTR_VAL(ZSTR_KNOWN(id)), ZSTR_LEN(ZSTR_KNOWN(id))); \
317
0
  }
318
319
ZEND_METHOD(Exception, __wakeup)
320
0
{
321
0
  zval value, *pvalue;
322
0
  zval *object = ZEND_THIS;
323
0
  CHECK_EXC_TYPE(ZEND_STR_MESSAGE,  IS_STRING);
324
0
  CHECK_EXC_TYPE(ZEND_STR_STRING,   IS_STRING);
325
0
  CHECK_EXC_TYPE(ZEND_STR_CODE,     IS_LONG);
326
0
  CHECK_EXC_TYPE(ZEND_STR_FILE,     IS_STRING);
327
0
  CHECK_EXC_TYPE(ZEND_STR_LINE,     IS_LONG);
328
  /* The type of $trace and $previous is enforced through typed properties. */
329
0
}
330
/* }}} */
331
332
/* {{{ proto ErrorException::__construct(string message, int code, int severity [, string filename [, int lineno [, Throwable previous]]])
333
   ErrorException constructor */
334
ZEND_METHOD(ErrorException, __construct)
335
0
{
336
0
  zend_string *message = NULL, *filename = NULL;
337
0
  zend_long   code = 0, severity = E_ERROR, lineno;
338
0
  zval   tmp, *object, *previous = NULL;
339
0
  int    argc = ZEND_NUM_ARGS();
340
341
0
  if (zend_parse_parameters(argc, "|SllSlO!", &message, &code, &severity, &filename, &lineno, &previous, zend_ce_throwable) == FAILURE) {
342
0
    RETURN_THROWS();
343
0
  }
344
345
0
  object = ZEND_THIS;
346
347
0
  if (message) {
348
0
    ZVAL_STR_COPY(&tmp, message);
349
0
    zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
350
0
    zval_ptr_dtor(&tmp);
351
0
  }
352
353
0
  if (code) {
354
0
    ZVAL_LONG(&tmp, code);
355
0
    zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_CODE), &tmp);
356
0
  }
357
358
0
  if (previous) {
359
0
    zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous);
360
0
  }
361
362
0
  ZVAL_LONG(&tmp, severity);
363
0
  zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_SEVERITY), &tmp);
364
365
0
  if (argc >= 4) {
366
0
    ZVAL_STR_COPY(&tmp, filename);
367
0
    zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
368
0
    zval_ptr_dtor(&tmp);
369
0
      if (argc < 5) {
370
0
          lineno = 0; /* invalidate lineno */
371
0
      }
372
0
    ZVAL_LONG(&tmp, lineno);
373
0
    zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
374
0
  }
375
0
}
376
/* }}} */
377
378
#define GET_PROPERTY(object, id) \
379
640
  zend_read_property_ex(i_get_exception_base(object), (object), ZSTR_KNOWN(id), 0, &rv)
380
#define GET_PROPERTY_SILENT(object, id) \
381
384
  zend_read_property_ex(i_get_exception_base(object), (object), ZSTR_KNOWN(id), 1, &rv)
382
383
/* {{{ proto string Exception|Error::getFile()
384
   Get the file in which the exception occurred */
385
ZEND_METHOD(Exception, getFile)
386
0
{
387
0
  zval *prop, rv;
388
389
0
  ZEND_PARSE_PARAMETERS_NONE();
390
391
0
  prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_FILE);
392
0
  RETURN_STR(zval_get_string(prop));
393
0
}
394
/* }}} */
395
396
/* {{{ proto int Exception|Error::getLine()
397
   Get the line in which the exception occurred */
398
ZEND_METHOD(Exception, getLine)
399
0
{
400
0
  zval *prop, rv;
401
402
0
  ZEND_PARSE_PARAMETERS_NONE();
403
404
0
  prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_LINE);
405
0
  RETURN_LONG(zval_get_long(prop));
406
0
}
407
/* }}} */
408
409
/* {{{ proto string Exception|Error::getMessage()
410
   Get the exception message */
411
ZEND_METHOD(Exception, getMessage)
412
0
{
413
0
  zval *prop, rv;
414
415
0
  ZEND_PARSE_PARAMETERS_NONE();
416
417
0
  prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_MESSAGE);
418
0
  RETURN_STR(zval_get_string(prop));
419
0
}
420
/* }}} */
421
422
/* {{{ proto int Exception|Error::getCode()
423
   Get the exception code */
424
ZEND_METHOD(Exception, getCode)
425
0
{
426
0
  zval *prop, rv;
427
428
0
  ZEND_PARSE_PARAMETERS_NONE();
429
430
0
  prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_CODE);
431
0
  ZVAL_DEREF(prop);
432
0
  ZVAL_COPY(return_value, prop);
433
0
}
434
/* }}} */
435
436
/* {{{ proto array Exception|Error::getTrace()
437
   Get the stack trace for the location in which the exception occurred */
438
ZEND_METHOD(Exception, getTrace)
439
0
{
440
0
  zval *prop, rv;
441
442
0
  ZEND_PARSE_PARAMETERS_NONE();
443
444
0
  prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_TRACE);
445
0
  ZVAL_DEREF(prop);
446
0
  ZVAL_COPY(return_value, prop);
447
0
}
448
/* }}} */
449
450
/* {{{ proto int ErrorException::getSeverity()
451
   Get the exception severity */
452
ZEND_METHOD(ErrorException, getSeverity)
453
0
{
454
0
  zval *prop, rv;
455
456
0
  ZEND_PARSE_PARAMETERS_NONE();
457
458
0
  prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_SEVERITY);
459
0
  ZVAL_DEREF(prop);
460
0
  ZVAL_COPY(return_value, prop);
461
0
}
462
/* }}} */
463
464
0
#define TRACE_APPEND_KEY(key) do {                                          \
465
0
    tmp = zend_hash_find(ht, key);                                      \
466
0
    if (tmp) {                                                          \
467
0
      if (Z_TYPE_P(tmp) != IS_STRING) {                               \
468
0
        zend_error(E_WARNING, "Value for %s is not a string",       \
469
0
          ZSTR_VAL(key));                                         \
470
0
        smart_str_appends(str, "[unknown]");                        \
471
0
      } else {                                                        \
472
0
        smart_str_appends(str, Z_STRVAL_P(tmp));                    \
473
0
      }                                                               \
474
0
    } \
475
0
  } while (0)
476
477
static void _build_trace_args(zval *arg, smart_str *str) /* {{{ */
478
0
{
479
  /* the trivial way would be to do
480
   * convert_to_string_ex(arg);
481
   * append it and kill the now tmp arg.
482
   * but that could cause some E_NOTICE and also damn long lines.
483
   */
484
485
0
  ZVAL_DEREF(arg);
486
0
  switch (Z_TYPE_P(arg)) {
487
0
    case IS_NULL:
488
0
      smart_str_appends(str, "NULL, ");
489
0
      break;
490
0
    case IS_STRING:
491
0
      smart_str_appendc(str, '\'');
492
0
      smart_str_append_escaped(str, Z_STRVAL_P(arg), MIN(Z_STRLEN_P(arg), 15));
493
0
      if (Z_STRLEN_P(arg) > 15) {
494
0
        smart_str_appends(str, "...', ");
495
0
      } else {
496
0
        smart_str_appends(str, "', ");
497
0
      }
498
0
      break;
499
0
    case IS_FALSE:
500
0
      smart_str_appends(str, "false, ");
501
0
      break;
502
0
    case IS_TRUE:
503
0
      smart_str_appends(str, "true, ");
504
0
      break;
505
0
    case IS_RESOURCE:
506
0
      smart_str_appends(str, "Resource id #");
507
0
      smart_str_append_long(str, Z_RES_HANDLE_P(arg));
508
0
      smart_str_appends(str, ", ");
509
0
      break;
510
0
    case IS_LONG:
511
0
      smart_str_append_long(str, Z_LVAL_P(arg));
512
0
      smart_str_appends(str, ", ");
513
0
      break;
514
0
    case IS_DOUBLE: {
515
0
      smart_str_append_printf(str, "%.*G", (int) EG(precision), Z_DVAL_P(arg));
516
0
      smart_str_appends(str, ", ");
517
0
      break;
518
0
    }
519
0
    case IS_ARRAY:
520
0
      smart_str_appends(str, "Array, ");
521
0
      break;
522
0
    case IS_OBJECT: {
523
0
      zend_string *class_name = Z_OBJ_HANDLER_P(arg, get_class_name)(Z_OBJ_P(arg));
524
0
      smart_str_appends(str, "Object(");
525
0
      smart_str_appends(str, ZSTR_VAL(class_name));
526
0
      smart_str_appends(str, "), ");
527
0
      zend_string_release_ex(class_name, 0);
528
0
      break;
529
0
    }
530
0
  }
531
0
}
532
/* }}} */
533
534
static void _build_trace_string(smart_str *str, HashTable *ht, uint32_t num) /* {{{ */
535
0
{
536
0
  zval *file, *tmp;
537
538
0
  smart_str_appendc(str, '#');
539
0
  smart_str_append_long(str, num);
540
0
  smart_str_appendc(str, ' ');
541
542
0
  file = zend_hash_find_ex(ht, ZSTR_KNOWN(ZEND_STR_FILE), 1);
543
0
  if (file) {
544
0
    if (Z_TYPE_P(file) != IS_STRING) {
545
0
      zend_error(E_WARNING, "Function name is not a string");
546
0
      smart_str_appends(str, "[unknown function]");
547
0
    } else{
548
0
      zend_long line;
549
0
      tmp = zend_hash_find_ex(ht, ZSTR_KNOWN(ZEND_STR_LINE), 1);
550
0
      if (tmp) {
551
0
        if (Z_TYPE_P(tmp) == IS_LONG) {
552
0
          line = Z_LVAL_P(tmp);
553
0
        } else {
554
0
          zend_error(E_WARNING, "Line is not an int");
555
0
          line = 0;
556
0
        }
557
0
      } else {
558
0
        line = 0;
559
0
      }
560
0
      smart_str_append(str, Z_STR_P(file));
561
0
      smart_str_appendc(str, '(');
562
0
      smart_str_append_long(str, line);
563
0
      smart_str_appends(str, "): ");
564
0
    }
565
0
  } else {
566
0
    smart_str_appends(str, "[internal function]: ");
567
0
  }
568
0
  TRACE_APPEND_KEY(ZSTR_KNOWN(ZEND_STR_CLASS));
569
0
  TRACE_APPEND_KEY(ZSTR_KNOWN(ZEND_STR_TYPE));
570
0
  TRACE_APPEND_KEY(ZSTR_KNOWN(ZEND_STR_FUNCTION));
571
0
  smart_str_appendc(str, '(');
572
0
  tmp = zend_hash_find_ex(ht, ZSTR_KNOWN(ZEND_STR_ARGS), 1);
573
0
  if (tmp) {
574
0
    if (Z_TYPE_P(tmp) == IS_ARRAY) {
575
0
      size_t last_len = ZSTR_LEN(str->s);
576
0
      zval *arg;
577
578
0
      ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(tmp), arg) {
579
0
        _build_trace_args(arg, str);
580
0
      } ZEND_HASH_FOREACH_END();
581
582
0
      if (last_len != ZSTR_LEN(str->s)) {
583
0
        ZSTR_LEN(str->s) -= 2; /* remove last ', ' */
584
0
      }
585
0
    } else {
586
0
      zend_error(E_WARNING, "args element is not an array");
587
0
    }
588
0
  }
589
0
  smart_str_appends(str, ")\n");
590
0
}
591
/* }}} */
592
593
/* {{{ proto string Exception|Error::getTraceAsString()
594
   Obtain the backtrace for the exception as a string (instead of an array) */
595
ZEND_METHOD(Exception, getTraceAsString)
596
128
{
597
128
  zval *trace, *frame, rv;
598
128
  zend_ulong index;
599
128
  zval *object;
600
128
  zend_class_entry *base_ce;
601
128
  smart_str str = {0};
602
128
  uint32_t num = 0;
603
604
128
  ZEND_PARSE_PARAMETERS_NONE();
605
606
128
  object = ZEND_THIS;
607
128
  base_ce = i_get_exception_base(object);
608
609
128
  trace = zend_read_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_TRACE), 1, &rv);
610
128
  if (EG(exception)) {
611
0
    RETURN_THROWS();
612
0
  }
613
614
  /* Type should be guaranteed by property type. */
615
128
  ZEND_ASSERT(Z_TYPE_P(trace) == IS_ARRAY);
616
128
  ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(trace), index, frame) {
617
0
    if (Z_TYPE_P(frame) != IS_ARRAY) {
618
0
      zend_error(E_WARNING, "Expected array for frame " ZEND_ULONG_FMT, index);
619
0
      continue;
620
0
    }
621
622
0
    _build_trace_string(&str, Z_ARRVAL_P(frame), num++);
623
0
  } ZEND_HASH_FOREACH_END();
624
625
128
  smart_str_appendc(&str, '#');
626
128
  smart_str_append_long(&str, num);
627
128
  smart_str_appends(&str, " {main}");
628
128
  smart_str_0(&str);
629
630
128
  RETURN_NEW_STR(str.s);
631
128
}
632
/* }}} */
633
634
/* {{{ proto Throwable Exception|Error::getPrevious()
635
   Return previous Throwable or NULL. */
636
ZEND_METHOD(Exception, getPrevious)
637
0
{
638
0
  zval rv;
639
640
0
  ZEND_PARSE_PARAMETERS_NONE();
641
642
0
  ZVAL_COPY(return_value, GET_PROPERTY_SILENT(ZEND_THIS, ZEND_STR_PREVIOUS));
643
0
} /* }}} */
644
645
/* {{{ proto string Exception|Error::__toString()
646
   Obtain the string representation of the Exception object */
647
ZEND_METHOD(Exception, __toString)
648
128
{
649
128
  zval trace, *exception;
650
128
  zend_class_entry *base_ce;
651
128
  zend_string *str;
652
128
  zend_fcall_info fci;
653
128
  zval rv, tmp;
654
128
  zend_string *fname;
655
656
128
  ZEND_PARSE_PARAMETERS_NONE();
657
658
128
  str = ZSTR_EMPTY_ALLOC();
659
660
128
  exception = ZEND_THIS;
661
128
  fname = zend_string_init("gettraceasstring", sizeof("gettraceasstring")-1, 0);
662
663
256
  while (exception && Z_TYPE_P(exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception), zend_ce_throwable)) {
664
128
    zend_string *prev_str = str;
665
128
    zend_string *message = zval_get_string(GET_PROPERTY(exception, ZEND_STR_MESSAGE));
666
128
    zend_string *file = zval_get_string(GET_PROPERTY(exception, ZEND_STR_FILE));
667
128
    zend_long line = zval_get_long(GET_PROPERTY(exception, ZEND_STR_LINE));
668
669
128
    fci.size = sizeof(fci);
670
128
    ZVAL_STR(&fci.function_name, fname);
671
128
    fci.object = Z_OBJ_P(exception);
672
128
    fci.retval = &trace;
673
128
    fci.param_count = 0;
674
128
    fci.params = NULL;
675
128
    fci.no_separation = 1;
676
677
128
    zend_call_function(&fci, NULL);
678
679
128
    if (Z_TYPE(trace) != IS_STRING) {
680
0
      zval_ptr_dtor(&trace);
681
0
      ZVAL_UNDEF(&trace);
682
0
    }
683
684
128
    if ((Z_OBJCE_P(exception) == zend_ce_type_error || Z_OBJCE_P(exception) == zend_ce_argument_count_error) && strstr(ZSTR_VAL(message), ", called in ")) {
685
0
      zend_string *real_message = zend_strpprintf(0, "%s and defined", ZSTR_VAL(message));
686
0
      zend_string_release_ex(message, 0);
687
0
      message = real_message;
688
0
    }
689
690
128
    if (ZSTR_LEN(message) > 0) {
691
128
      str = zend_strpprintf(0, "%s: %s in %s:" ZEND_LONG_FMT
692
128
          "\nStack trace:\n%s%s%s",
693
128
          ZSTR_VAL(Z_OBJCE_P(exception)->name), ZSTR_VAL(message), ZSTR_VAL(file), line,
694
128
          (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n",
695
128
          ZSTR_LEN(prev_str) ? "\n\nNext " : "", ZSTR_VAL(prev_str));
696
0
    } else {
697
0
      str = zend_strpprintf(0, "%s in %s:" ZEND_LONG_FMT
698
0
          "\nStack trace:\n%s%s%s",
699
0
          ZSTR_VAL(Z_OBJCE_P(exception)->name), ZSTR_VAL(file), line,
700
0
          (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n",
701
0
          ZSTR_LEN(prev_str) ? "\n\nNext " : "", ZSTR_VAL(prev_str));
702
0
    }
703
704
128
    zend_string_release_ex(prev_str, 0);
705
128
    zend_string_release_ex(message, 0);
706
128
    zend_string_release_ex(file, 0);
707
128
    zval_ptr_dtor(&trace);
708
709
128
    Z_PROTECT_RECURSION_P(exception);
710
128
    exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS);
711
128
    if (exception && Z_TYPE_P(exception) == IS_OBJECT && Z_IS_RECURSIVE_P(exception)) {
712
0
      break;
713
0
    }
714
128
  }
715
128
  zend_string_release_ex(fname, 0);
716
717
128
  exception = ZEND_THIS;
718
  /* Reset apply counts */
719
256
  while (exception && Z_TYPE_P(exception) == IS_OBJECT && (base_ce = i_get_exception_base(exception)) && instanceof_function(Z_OBJCE_P(exception), base_ce)) {
720
128
    if (Z_IS_RECURSIVE_P(exception)) {
721
128
      Z_UNPROTECT_RECURSION_P(exception);
722
0
    } else {
723
0
      break;
724
0
    }
725
128
    exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS);
726
128
  }
727
728
128
  exception = ZEND_THIS;
729
128
  base_ce = i_get_exception_base(exception);
730
731
  /* We store the result in the private property string so we can access
732
   * the result in uncaught exception handlers without memleaks. */
733
128
  ZVAL_STR(&tmp, str);
734
128
  zend_update_property_ex(base_ce, exception, ZSTR_KNOWN(ZEND_STR_STRING), &tmp);
735
736
128
  RETURN_STR(str);
737
128
}
738
/* }}} */
739
740
static void declare_exception_properties(zend_class_entry *ce)
741
7.36k
{
742
7.36k
  zval val;
743
744
7.36k
  zend_declare_property_string(ce, "message", sizeof("message")-1, "", ZEND_ACC_PROTECTED);
745
7.36k
  zend_declare_property_string(ce, "string", sizeof("string")-1, "", ZEND_ACC_PRIVATE);
746
7.36k
  zend_declare_property_long(ce, "code", sizeof("code")-1, 0, ZEND_ACC_PROTECTED);
747
7.36k
  zend_declare_property_null(ce, "file", sizeof("file")-1, ZEND_ACC_PROTECTED);
748
7.36k
  zend_declare_property_null(ce, "line", sizeof("line")-1, ZEND_ACC_PROTECTED);
749
750
7.36k
  ZVAL_EMPTY_ARRAY(&val);
751
7.36k
  zend_declare_typed_property(
752
7.36k
    ce, ZSTR_KNOWN(ZEND_STR_TRACE), &val, ZEND_ACC_PRIVATE, NULL,
753
7.36k
    (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY));
754
755
7.36k
  ZVAL_NULL(&val);
756
7.36k
  zend_declare_typed_property(
757
7.36k
    ce, ZSTR_KNOWN(ZEND_STR_PREVIOUS), &val, ZEND_ACC_PRIVATE, NULL,
758
7.36k
    (zend_type) ZEND_TYPE_INIT_CE(zend_ce_throwable, /* allow_null */ 1, 0));
759
7.36k
}
760
761
void zend_register_default_exception(void) /* {{{ */
762
3.68k
{
763
3.68k
  zend_class_entry ce;
764
765
3.68k
  REGISTER_MAGIC_INTERFACE(throwable, Throwable);
766
3.68k
  zend_class_implements(zend_ce_throwable, 1, zend_ce_stringable);
767
768
3.68k
  memcpy(&default_exception_handlers, &std_object_handlers, sizeof(zend_object_handlers));
769
3.68k
  default_exception_handlers.clone_obj = NULL;
770
771
3.68k
  INIT_CLASS_ENTRY(ce, "Exception", class_Exception_methods);
772
3.68k
  zend_ce_exception = zend_register_internal_class_ex(&ce, NULL);
773
3.68k
  zend_ce_exception->create_object = zend_default_exception_new;
774
3.68k
  zend_class_implements(zend_ce_exception, 1, zend_ce_throwable);
775
3.68k
  declare_exception_properties(zend_ce_exception);
776
777
3.68k
  INIT_CLASS_ENTRY(ce, "ErrorException", class_ErrorException_methods);
778
3.68k
  zend_ce_error_exception = zend_register_internal_class_ex(&ce, zend_ce_exception);
779
3.68k
  zend_ce_error_exception->create_object = zend_error_exception_new;
780
3.68k
  zend_declare_property_long(zend_ce_error_exception, "severity", sizeof("severity")-1, E_ERROR, ZEND_ACC_PROTECTED);
781
782
3.68k
  INIT_CLASS_ENTRY(ce, "Error", class_Error_methods);
783
3.68k
  zend_ce_error = zend_register_internal_class_ex(&ce, NULL);
784
3.68k
  zend_ce_error->create_object = zend_default_exception_new;
785
3.68k
  zend_class_implements(zend_ce_error, 1, zend_ce_throwable);
786
3.68k
  declare_exception_properties(zend_ce_error);
787
788
3.68k
  INIT_CLASS_ENTRY(ce, "CompileError", class_CompileError_methods);
789
3.68k
  zend_ce_compile_error = zend_register_internal_class_ex(&ce, zend_ce_error);
790
3.68k
  zend_ce_compile_error->create_object = zend_default_exception_new;
791
792
3.68k
  INIT_CLASS_ENTRY(ce, "ParseError", class_ParseError_methods);
793
3.68k
  zend_ce_parse_error = zend_register_internal_class_ex(&ce, zend_ce_compile_error);
794
3.68k
  zend_ce_parse_error->create_object = zend_default_exception_new;
795
796
3.68k
  INIT_CLASS_ENTRY(ce, "TypeError", class_TypeError_methods);
797
3.68k
  zend_ce_type_error = zend_register_internal_class_ex(&ce, zend_ce_error);
798
3.68k
  zend_ce_type_error->create_object = zend_default_exception_new;
799
800
3.68k
  INIT_CLASS_ENTRY(ce, "ArgumentCountError", class_ArgumentCountError_methods);
801
3.68k
  zend_ce_argument_count_error = zend_register_internal_class_ex(&ce, zend_ce_type_error);
802
3.68k
  zend_ce_argument_count_error->create_object = zend_default_exception_new;
803
804
3.68k
  INIT_CLASS_ENTRY(ce, "ValueError", class_ValueError_methods);
805
3.68k
  zend_ce_value_error = zend_register_internal_class_ex(&ce, zend_ce_error);
806
3.68k
  zend_ce_value_error->create_object = zend_default_exception_new;
807
808
3.68k
  INIT_CLASS_ENTRY(ce, "ArithmeticError", class_ArithmeticError_methods);
809
3.68k
  zend_ce_arithmetic_error = zend_register_internal_class_ex(&ce, zend_ce_error);
810
3.68k
  zend_ce_arithmetic_error->create_object = zend_default_exception_new;
811
812
3.68k
  INIT_CLASS_ENTRY(ce, "DivisionByZeroError", class_DivisionByZeroError_methods);
813
3.68k
  zend_ce_division_by_zero_error = zend_register_internal_class_ex(&ce, zend_ce_arithmetic_error);
814
3.68k
  zend_ce_division_by_zero_error->create_object = zend_default_exception_new;
815
816
3.68k
  INIT_CLASS_ENTRY(zend_ce_unwind_exit, "UnwindExit", NULL);
817
3.68k
}
818
/* }}} */
819
820
/* {{{ Deprecated - Use zend_ce_exception directly instead */
821
ZEND_API zend_class_entry *zend_exception_get_default(void)
822
0
{
823
0
  return zend_ce_exception;
824
0
}
825
/* }}} */
826
827
/* {{{ Deprecated - Use zend_ce_error_exception directly instead */
828
ZEND_API zend_class_entry *zend_get_error_exception(void)
829
0
{
830
0
  return zend_ce_error_exception;
831
0
}
832
/* }}} */
833
834
static zend_object *zend_throw_exception_zstr(zend_class_entry *exception_ce, zend_string *message, zend_long code) /* {{{ */
835
1.55M
{
836
1.55M
  zval ex, tmp;
837
838
1.55M
  if (exception_ce) {
839
1.55M
    if (!instanceof_function(exception_ce, zend_ce_throwable)) {
840
0
      zend_error(E_NOTICE, "Exceptions must implement Throwable");
841
0
      exception_ce = zend_ce_exception;
842
0
    }
843
0
  } else {
844
0
    exception_ce = zend_ce_exception;
845
0
  }
846
1.55M
  object_init_ex(&ex, exception_ce);
847
848
849
1.55M
  if (message) {
850
1.55M
    ZVAL_STR(&tmp, message);
851
1.55M
    zend_update_property_ex(exception_ce, &ex, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
852
1.55M
  }
853
1.55M
  if (code) {
854
0
    ZVAL_LONG(&tmp, code);
855
0
    zend_update_property_ex(exception_ce, &ex, ZSTR_KNOWN(ZEND_STR_CODE), &tmp);
856
0
  }
857
858
1.55M
  zend_throw_exception_internal(&ex);
859
1.55M
  return Z_OBJ(ex);
860
1.55M
}
861
/* }}} */
862
863
ZEND_API ZEND_COLD zend_object *zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code) /* {{{ */
864
1.55M
{
865
1.55M
  zend_string *msg_str = message ? zend_string_init(message, strlen(message), 0) : NULL;
866
1.55M
  zend_object *ex = zend_throw_exception_zstr(exception_ce, msg_str, code);
867
1.55M
  if (msg_str) {
868
1.55M
    zend_string_release(msg_str);
869
1.55M
  }
870
1.55M
  return ex;
871
1.55M
}
872
/* }}} */
873
874
ZEND_API ZEND_COLD zend_object *zend_throw_exception_ex(zend_class_entry *exception_ce, zend_long code, const char *format, ...) /* {{{ */
875
23.9k
{
876
23.9k
  va_list arg;
877
23.9k
  char *message;
878
23.9k
  zend_object *obj;
879
880
23.9k
  va_start(arg, format);
881
23.9k
  zend_vspprintf(&message, 0, format, arg);
882
23.9k
  va_end(arg);
883
23.9k
  obj = zend_throw_exception(exception_ce, message, code);
884
23.9k
  efree(message);
885
23.9k
  return obj;
886
23.9k
}
887
/* }}} */
888
889
ZEND_API ZEND_COLD zend_object *zend_throw_error_exception(zend_class_entry *exception_ce, zend_string *message, zend_long code, int severity) /* {{{ */
890
0
{
891
0
  zval ex, tmp;
892
0
  zend_object *obj = zend_throw_exception_zstr(exception_ce, message, code);
893
0
  ZVAL_OBJ(&ex, obj);
894
0
  ZVAL_LONG(&tmp, severity);
895
0
  zend_update_property_ex(zend_ce_error_exception, &ex, ZSTR_KNOWN(ZEND_STR_SEVERITY), &tmp);
896
0
  return obj;
897
0
}
898
/* }}} */
899
900
static void zend_error_va(int type, const char *file, uint32_t lineno, const char *format, ...) /* {{{ */
901
128
{
902
128
  va_list args;
903
128
  va_start(args, format);
904
128
  zend_string *message = zend_vstrpprintf(0, format, args);
905
128
  zend_error_cb(type, file, lineno, message);
906
128
  zend_string_release(message);
907
128
  va_end(args);
908
128
}
909
/* }}} */
910
911
/* This function doesn't return if it uses E_ERROR */
912
ZEND_API ZEND_COLD int zend_exception_error(zend_object *ex, int severity) /* {{{ */
913
128
{
914
128
  zval exception, rv;
915
128
  zend_class_entry *ce_exception;
916
128
  int result = FAILURE;
917
918
128
  ZVAL_OBJ(&exception, ex);
919
128
  ce_exception = ex->ce;
920
128
  EG(exception) = NULL;
921
128
  if (ce_exception == zend_ce_parse_error || ce_exception == zend_ce_compile_error) {
922
0
    zend_string *message = zval_get_string(GET_PROPERTY(&exception, ZEND_STR_MESSAGE));
923
0
    zend_string *file = zval_get_string(GET_PROPERTY_SILENT(&exception, ZEND_STR_FILE));
924
0
    zend_long line = zval_get_long(GET_PROPERTY_SILENT(&exception, ZEND_STR_LINE));
925
926
0
    zend_error_cb(
927
0
      (ce_exception == zend_ce_parse_error ? E_PARSE : E_COMPILE_ERROR) | E_DONT_BAIL,
928
0
      ZSTR_VAL(file), line, message);
929
930
0
    zend_string_release_ex(file, 0);
931
0
    zend_string_release_ex(message, 0);
932
128
  } else if (instanceof_function(ce_exception, zend_ce_throwable)) {
933
128
    zval tmp;
934
128
    zend_string *str, *file = NULL;
935
128
    zend_long line = 0;
936
937
128
    zend_call_known_instance_method_with_0_params(ex->ce->__tostring, Z_OBJ(exception), &tmp);
938
128
    if (!EG(exception)) {
939
128
      if (Z_TYPE(tmp) != IS_STRING) {
940
0
        zend_error(E_WARNING, "%s::__toString() must return a string", ZSTR_VAL(ce_exception->name));
941
128
      } else {
942
128
        zend_update_property_ex(i_get_exception_base(&exception), &exception, ZSTR_KNOWN(ZEND_STR_STRING), &tmp);
943
128
      }
944
128
    }
945
128
    zval_ptr_dtor(&tmp);
946
947
128
    if (EG(exception)) {
948
0
      zval zv;
949
950
0
      ZVAL_OBJ(&zv, EG(exception));
951
      /* do the best we can to inform about the inner exception */
952
0
      if (instanceof_function(ce_exception, zend_ce_exception) || instanceof_function(ce_exception, zend_ce_error)) {
953
0
        file = zval_get_string(GET_PROPERTY_SILENT(&zv, ZEND_STR_FILE));
954
0
        line = zval_get_long(GET_PROPERTY_SILENT(&zv, ZEND_STR_LINE));
955
0
      }
956
957
0
      zend_error_va(E_WARNING, (file && ZSTR_LEN(file) > 0) ? ZSTR_VAL(file) : NULL, line,
958
0
        "Uncaught %s in exception handling during call to %s::__tostring()",
959
0
        ZSTR_VAL(Z_OBJCE(zv)->name), ZSTR_VAL(ce_exception->name));
960
961
0
      if (file) {
962
0
        zend_string_release_ex(file, 0);
963
0
      }
964
0
    }
965
966
128
    str = zval_get_string(GET_PROPERTY_SILENT(&exception, ZEND_STR_STRING));
967
128
    file = zval_get_string(GET_PROPERTY_SILENT(&exception, ZEND_STR_FILE));
968
128
    line = zval_get_long(GET_PROPERTY_SILENT(&exception, ZEND_STR_LINE));
969
970
128
    zend_error_va(severity | E_DONT_BAIL,
971
128
      (file && ZSTR_LEN(file) > 0) ? ZSTR_VAL(file) : NULL, line,
972
128
      "Uncaught %s\n  thrown", ZSTR_VAL(str));
973
974
128
    zend_string_release_ex(str, 0);
975
128
    zend_string_release_ex(file, 0);
976
0
  } else if (ce_exception == &zend_ce_unwind_exit) {
977
    /* We successfully unwound, nothing more to do */
978
0
    result = SUCCESS;
979
0
  } else {
980
0
    zend_error(severity, "Uncaught exception '%s'", ZSTR_VAL(ce_exception->name));
981
0
  }
982
983
128
  OBJ_RELEASE(ex);
984
128
  return result;
985
128
}
986
/* }}} */
987
988
ZEND_API ZEND_COLD void zend_throw_exception_object(zval *exception) /* {{{ */
989
0
{
990
0
  zend_class_entry *exception_ce;
991
992
0
  if (exception == NULL || Z_TYPE_P(exception) != IS_OBJECT) {
993
0
    zend_error_noreturn(E_CORE_ERROR, "Need to supply an object when throwing an exception");
994
0
  }
995
996
0
  exception_ce = Z_OBJCE_P(exception);
997
998
0
  if (!exception_ce || !instanceof_function(exception_ce, zend_ce_throwable)) {
999
0
    zend_throw_error(NULL, "Cannot throw objects that do not implement Throwable");
1000
0
    zval_ptr_dtor(exception);
1001
0
    return;
1002
0
  }
1003
0
  zend_throw_exception_internal(exception);
1004
0
}
1005
/* }}} */
1006
1007
ZEND_API ZEND_COLD void zend_throw_unwind_exit()
1008
0
{
1009
0
  ZEND_ASSERT(!EG(exception));
1010
0
  EG(exception) = zend_objects_new(&zend_ce_unwind_exit);
1011
0
  EG(opline_before_exception) = EG(current_execute_data)->opline;
1012
0
  EG(current_execute_data)->opline = EG(exception_op);
1013
0
}
1014
1015
ZEND_API zend_bool zend_is_unwind_exit(zend_object *ex)
1016
0
{
1017
0
  return ex->ce == &zend_ce_unwind_exit;
1018
0
}