root/Zend/zend_exceptions.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_implement_throwable
  2. i_get_exception_base
  3. zend_get_exception_base
  4. zend_exception_set_previous
  5. zend_exception_save
  6. zend_exception_restore
  7. zend_throw_exception_internal
  8. zend_clear_exception
  9. zend_default_exception_new_ex
  10. zend_default_exception_new
  11. zend_error_exception_new
  12. ZEND_METHOD
  13. ZEND_METHOD
  14. ZEND_METHOD
  15. ZEND_METHOD
  16. ZEND_METHOD
  17. ZEND_METHOD
  18. ZEND_METHOD
  19. ZEND_METHOD
  20. ZEND_METHOD
  21. ZEND_METHOD
  22. compute_escaped_string_len
  23. smart_str_append_escaped
  24. _build_trace_args
  25. _build_trace_string
  26. ZEND_METHOD
  27. ZEND_METHOD
  28. zend_spprintf
  29. zend_strpprintf
  30. ZEND_METHOD
  31. zend_register_default_exception
  32. zend_exception_get_default
  33. zend_get_error_exception
  34. zend_throw_exception
  35. zend_throw_exception_ex
  36. zend_throw_error_exception
  37. zend_error_va
  38. zend_error_helper
  39. zend_exception_error
  40. zend_throw_exception_object

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend Engine                                                          |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 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@zend.com>                                |
  16    |          Marcus Boerger <helly@php.net>                              |
  17    |          Sterling Hughes <sterling@php.net>                          |
  18    |          Zeev Suraski <zeev@zend.com>                                |
  19    +----------------------------------------------------------------------+
  20 */
  21 
  22 /* $Id$ */
  23 
  24 #include "zend.h"
  25 #include "zend_API.h"
  26 #include "zend_builtin_functions.h"
  27 #include "zend_interfaces.h"
  28 #include "zend_exceptions.h"
  29 #include "zend_vm.h"
  30 #include "zend_dtrace.h"
  31 #include "zend_smart_str.h"
  32 
  33 ZEND_API zend_class_entry *zend_ce_throwable;
  34 ZEND_API zend_class_entry *zend_ce_exception;
  35 ZEND_API zend_class_entry *zend_ce_error_exception;
  36 ZEND_API zend_class_entry *zend_ce_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_arithmetic_error;
  40 ZEND_API zend_class_entry *zend_ce_division_by_zero_error;
  41 
  42 ZEND_API void (*zend_throw_exception_hook)(zval *ex);
  43 
  44 static zend_object_handlers default_exception_handlers;
  45 
  46 /* {{{ zend_implement_throwable */
  47 static int zend_implement_throwable(zend_class_entry *interface, zend_class_entry *class_type)
  48 {
  49         if (instanceof_function(class_type, zend_ce_exception) || instanceof_function(class_type, zend_ce_error)) {
  50                 return SUCCESS;
  51         }
  52         zend_error_noreturn(E_ERROR, "Class %s cannot implement interface %s, extend %s or %s instead",
  53                 ZSTR_VAL(class_type->name),
  54                 ZSTR_VAL(interface->name),
  55                 ZSTR_VAL(zend_ce_exception->name),
  56                 ZSTR_VAL(zend_ce_error->name));
  57         return FAILURE;
  58 }
  59 /* }}} */
  60 
  61 static inline zend_class_entry *i_get_exception_base(zval *object)
  62 {
  63         return instanceof_function(Z_OBJCE_P(object), zend_ce_exception) ? zend_ce_exception : zend_ce_error;
  64 }
  65 
  66 ZEND_API zend_class_entry *zend_get_exception_base(zval *object)
  67 {
  68         return i_get_exception_base(object);
  69 }
  70 
  71 void zend_exception_set_previous(zend_object *exception, zend_object *add_previous)
  72 {
  73     zval *previous, *ancestor, *ex;
  74         zval  pv, zv, rv;
  75         zend_class_entry *base_ce;
  76 
  77         if (exception == add_previous || !add_previous || !exception) {
  78                 return;
  79         }
  80         ZVAL_OBJ(&pv, add_previous);
  81         if (!instanceof_function(Z_OBJCE(pv), zend_ce_throwable)) {
  82                 zend_error_noreturn(E_CORE_ERROR, "Previous exception must implement Throwable");
  83                 return;
  84         }
  85         ZVAL_OBJ(&zv, exception);
  86         ex = &zv;
  87         do {
  88                 ancestor = zend_read_property(i_get_exception_base(&pv), &pv, "previous", sizeof("previous")-1, 1, &rv);
  89                 while (Z_TYPE_P(ancestor) == IS_OBJECT) {
  90                         if (Z_OBJ_P(ancestor) == Z_OBJ_P(ex)) {
  91                                 OBJ_RELEASE(add_previous);
  92                                 return;
  93                         }
  94                         ancestor = zend_read_property(i_get_exception_base(ancestor), ancestor, "previous", sizeof("previous")-1, 1, &rv);
  95                 }
  96                 base_ce = i_get_exception_base(ex);
  97                 previous = zend_read_property(base_ce, ex, "previous", sizeof("previous")-1, 1, &rv);
  98                 if (Z_TYPE_P(previous) == IS_NULL) {
  99                         zend_update_property(base_ce, ex, "previous", sizeof("previous")-1, &pv);
 100                         GC_REFCOUNT(add_previous)--;
 101                         return;
 102                 }
 103                 ex = previous;
 104         } while (Z_OBJ_P(ex) != add_previous);
 105 }
 106 
 107 void zend_exception_save(void) /* {{{ */
 108 {
 109         if (EG(prev_exception)) {
 110                 zend_exception_set_previous(EG(exception), EG(prev_exception));
 111         }
 112         if (EG(exception)) {
 113                 EG(prev_exception) = EG(exception);
 114         }
 115         EG(exception) = NULL;
 116 }
 117 /* }}} */
 118 
 119 void zend_exception_restore(void) /* {{{ */
 120 {
 121         if (EG(prev_exception)) {
 122                 if (EG(exception)) {
 123                         zend_exception_set_previous(EG(exception), EG(prev_exception));
 124                 } else {
 125                         EG(exception) = EG(prev_exception);
 126                 }
 127                 EG(prev_exception) = NULL;
 128         }
 129 }
 130 /* }}} */
 131 
 132 ZEND_API ZEND_COLD void zend_throw_exception_internal(zval *exception) /* {{{ */
 133 {
 134 #ifdef HAVE_DTRACE
 135         if (DTRACE_EXCEPTION_THROWN_ENABLED()) {
 136                 if (exception != NULL) {
 137                         DTRACE_EXCEPTION_THROWN(ZSTR_VAL(Z_OBJ_P(exception)->ce->name));
 138                 } else {
 139                         DTRACE_EXCEPTION_THROWN(NULL);
 140                 }
 141         }
 142 #endif /* HAVE_DTRACE */
 143 
 144         if (exception != NULL) {
 145                 zend_object *previous = EG(exception);
 146                 zend_exception_set_previous(Z_OBJ_P(exception), EG(exception));
 147                 EG(exception) = Z_OBJ_P(exception);
 148                 if (previous) {
 149                         return;
 150                 }
 151         }
 152         if (!EG(current_execute_data)) {
 153                 if (exception && Z_OBJCE_P(exception) == zend_ce_parse_error) {
 154                         return;
 155                 }
 156                 if(EG(exception)) {
 157                         zend_exception_error(EG(exception), E_ERROR);
 158                 }
 159                 zend_error_noreturn(E_CORE_ERROR, "Exception thrown without a stack frame");
 160         }
 161 
 162         if (zend_throw_exception_hook) {
 163                 zend_throw_exception_hook(exception);
 164         }
 165 
 166         if (!EG(current_execute_data)->func ||
 167             !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
 168             EG(current_execute_data)->opline->opcode == ZEND_HANDLE_EXCEPTION) {
 169                 /* no need to rethrow the exception */
 170                 return;
 171         }
 172         EG(opline_before_exception) = EG(current_execute_data)->opline;
 173         EG(current_execute_data)->opline = EG(exception_op);
 174 }
 175 /* }}} */
 176 
 177 ZEND_API void zend_clear_exception(void) /* {{{ */
 178 {
 179         if (EG(prev_exception)) {
 180 
 181                 OBJ_RELEASE(EG(prev_exception));
 182                 EG(prev_exception) = NULL;
 183         }
 184         if (!EG(exception)) {
 185                 return;
 186         }
 187         OBJ_RELEASE(EG(exception));
 188         EG(exception) = NULL;
 189         EG(current_execute_data)->opline = EG(opline_before_exception);
 190 #if ZEND_DEBUG
 191         EG(opline_before_exception) = NULL;
 192 #endif
 193 }
 194 /* }}} */
 195 
 196 static zend_object *zend_default_exception_new_ex(zend_class_entry *class_type, int skip_top_traces) /* {{{ */
 197 {
 198         zval obj;
 199         zend_object *object;
 200         zval trace;
 201         zend_class_entry *base_ce;
 202         zend_string *filename;
 203 
 204         Z_OBJ(obj) = object = zend_objects_new(class_type);
 205         Z_OBJ_HT(obj) = &default_exception_handlers;
 206 
 207         object_properties_init(object, class_type);
 208 
 209         if (EG(current_execute_data)) {
 210                 zend_fetch_debug_backtrace(&trace, skip_top_traces, 0, 0);
 211         } else {
 212                 array_init(&trace);
 213         }
 214         Z_SET_REFCOUNT(trace, 0);
 215 
 216         base_ce = i_get_exception_base(&obj);
 217 
 218         if (EXPECTED(class_type != zend_ce_parse_error || !(filename = zend_get_compiled_filename()))) {
 219                 zend_update_property_string(base_ce, &obj, "file", sizeof("file")-1, zend_get_executed_filename());
 220                 zend_update_property_long(base_ce, &obj, "line", sizeof("line")-1, zend_get_executed_lineno());
 221         } else {
 222                 zend_update_property_str(base_ce, &obj, "file", sizeof("file")-1, filename);
 223                 zend_update_property_long(base_ce, &obj, "line", sizeof("line")-1, zend_get_compiled_lineno());
 224         }
 225         zend_update_property(base_ce, &obj, "trace", sizeof("trace")-1, &trace);
 226 
 227         return object;
 228 }
 229 /* }}} */
 230 
 231 static zend_object *zend_default_exception_new(zend_class_entry *class_type) /* {{{ */
 232 {
 233         return zend_default_exception_new_ex(class_type, 0);
 234 }
 235 /* }}} */
 236 
 237 static zend_object *zend_error_exception_new(zend_class_entry *class_type) /* {{{ */
 238 {
 239         return zend_default_exception_new_ex(class_type, 2);
 240 }
 241 /* }}} */
 242 
 243 /* {{{ proto Exception|Error Exception|Error::__clone()
 244    Clone the exception object */
 245 ZEND_COLD ZEND_METHOD(exception, __clone)
 246 {
 247         /* Should never be executable */
 248         zend_throw_exception(NULL, "Cannot clone object using __clone()", 0);
 249 }
 250 /* }}} */
 251 
 252 /* {{{ proto Exception|Error::__construct(string message, int code [, Throwable previous])
 253    Exception constructor */
 254 ZEND_METHOD(exception, __construct)
 255 {
 256         zend_string *message = NULL;
 257         zend_long   code = 0;
 258         zval  *object, *previous = NULL;
 259         zend_class_entry *base_ce;
 260         int    argc = ZEND_NUM_ARGS();
 261 
 262         object = getThis();
 263         base_ce = i_get_exception_base(object);
 264 
 265         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc, "|SlO!", &message, &code, &previous, zend_ce_throwable) == FAILURE) {
 266                 zend_class_entry *ce;
 267 
 268                 if (execute_data->called_scope) {
 269                         ce = execute_data->called_scope;
 270                 } else {
 271                         ce = base_ce;
 272                 }
 273                 zend_throw_error(NULL, "Wrong parameters for %s([string $message [, long $code [, Throwable $previous = NULL]]])", ZSTR_VAL(ce->name));
 274                 return;
 275         }
 276 
 277         if (message) {
 278                 zend_update_property_str(base_ce, object, "message", sizeof("message")-1, message);
 279         }
 280 
 281         if (code) {
 282                 zend_update_property_long(base_ce, object, "code", sizeof("code")-1, code);
 283         }
 284 
 285         if (previous) {
 286                 zend_update_property(base_ce, object, "previous", sizeof("previous")-1, previous);
 287         }
 288 }
 289 /* }}} */
 290 
 291 /* {{{ proto Exception::__wakeup()
 292    Exception unserialize checks */
 293 #define CHECK_EXC_TYPE(name, type) \
 294         ZVAL_UNDEF(&value); \
 295         pvalue = zend_read_property(i_get_exception_base(object), (object), name, sizeof(name) - 1, 1, &value); \
 296         if(Z_TYPE_P(pvalue) != IS_UNDEF && Z_TYPE_P(pvalue) != type) { \
 297                 zval tmp; \
 298                 ZVAL_STRINGL(&tmp, name, sizeof(name) - 1); \
 299                 Z_OBJ_HANDLER_P(object, unset_property)(object, &tmp, NULL); \
 300                 zval_ptr_dtor(&tmp); \
 301         }
 302 
 303 ZEND_METHOD(exception, __wakeup)
 304 {
 305         zval value, *pvalue;
 306         zval *object = getThis();
 307         CHECK_EXC_TYPE("message", IS_STRING);
 308         CHECK_EXC_TYPE("string", IS_STRING);
 309         CHECK_EXC_TYPE("code", IS_LONG);
 310         CHECK_EXC_TYPE("file", IS_STRING);
 311         CHECK_EXC_TYPE("line", IS_LONG);
 312         CHECK_EXC_TYPE("trace", IS_ARRAY);
 313         CHECK_EXC_TYPE("previous", IS_OBJECT);
 314 }
 315 /* }}} */
 316 
 317 /* {{{ proto ErrorException::__construct(string message, int code, int severity [, string filename [, int lineno [, Throwable previous]]])
 318    ErrorException constructor */
 319 ZEND_METHOD(error_exception, __construct)
 320 {
 321         char  *message = NULL, *filename = NULL;
 322         zend_long   code = 0, severity = E_ERROR, lineno;
 323         zval  *object, *previous = NULL;
 324         int    argc = ZEND_NUM_ARGS();
 325         size_t message_len, filename_len;
 326 
 327         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc, "|sllslO!", &message, &message_len, &code, &severity, &filename, &filename_len, &lineno, &previous, zend_ce_throwable) == FAILURE) {
 328                 zend_class_entry *ce;
 329 
 330                 if (execute_data->called_scope) {
 331                         ce = execute_data->called_scope;
 332                 } else {
 333                         ce = zend_ce_error_exception;
 334                 }
 335                 zend_throw_error(NULL, "Wrong parameters for %s([string $message [, long $code, [ long $severity, [ string $filename, [ long $lineno  [, Throwable $previous = NULL]]]]]])", ZSTR_VAL(ce->name));
 336                 return;
 337         }
 338 
 339         object = getThis();
 340 
 341         if (message) {
 342                 zend_update_property_string(zend_ce_exception, object, "message", sizeof("message")-1, message);
 343         }
 344 
 345         if (code) {
 346                 zend_update_property_long(zend_ce_exception, object, "code", sizeof("code")-1, code);
 347         }
 348 
 349         if (previous) {
 350                 zend_update_property(zend_ce_exception, object, "previous", sizeof("previous")-1, previous);
 351         }
 352 
 353         zend_update_property_long(zend_ce_error_exception, object, "severity", sizeof("severity")-1, severity);
 354 
 355         if (argc >= 4) {
 356             zend_update_property_string(zend_ce_exception, object, "file", sizeof("file")-1, filename);
 357         if (argc < 5) {
 358             lineno = 0; /* invalidate lineno */
 359         }
 360                 zend_update_property_long(zend_ce_exception, object, "line", sizeof("line")-1, lineno);
 361         }
 362 }
 363 /* }}} */
 364 
 365 #define DEFAULT_0_PARAMS \
 366         if (zend_parse_parameters_none() == FAILURE) { \
 367                 return; \
 368         }
 369 
 370 #define GET_PROPERTY(object, name) \
 371         zend_read_property(i_get_exception_base(object), (object), name, sizeof(name) - 1, 0, &rv)
 372 #define GET_PROPERTY_SILENT(object, name) \
 373         zend_read_property(i_get_exception_base(object), (object), name, sizeof(name) - 1, 1, &rv)
 374 
 375 /* {{{ proto string Exception|Error::getFile()
 376    Get the file in which the exception occurred */
 377 ZEND_METHOD(exception, getFile)
 378 {
 379         zval rv;
 380 
 381         DEFAULT_0_PARAMS;
 382 
 383         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "file"));
 384 }
 385 /* }}} */
 386 
 387 /* {{{ proto int Exception|Error::getLine()
 388    Get the line in which the exception occurred */
 389 ZEND_METHOD(exception, getLine)
 390 {
 391         zval rv;
 392 
 393         DEFAULT_0_PARAMS;
 394 
 395         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "line"));
 396 }
 397 /* }}} */
 398 
 399 /* {{{ proto string Exception|Error::getMessage()
 400    Get the exception message */
 401 ZEND_METHOD(exception, getMessage)
 402 {
 403         zval rv;
 404 
 405         DEFAULT_0_PARAMS;
 406 
 407         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "message"));
 408 }
 409 /* }}} */
 410 
 411 /* {{{ proto int Exception|Error::getCode()
 412    Get the exception code */
 413 ZEND_METHOD(exception, getCode)
 414 {
 415         zval rv;
 416 
 417         DEFAULT_0_PARAMS;
 418 
 419         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "code"));
 420 }
 421 /* }}} */
 422 
 423 /* {{{ proto array Exception|Error::getTrace()
 424    Get the stack trace for the location in which the exception occurred */
 425 ZEND_METHOD(exception, getTrace)
 426 {
 427         zval rv;
 428 
 429         DEFAULT_0_PARAMS;
 430 
 431         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "trace"));
 432 }
 433 /* }}} */
 434 
 435 /* {{{ proto int ErrorException::getSeverity()
 436    Get the exception severity */
 437 ZEND_METHOD(error_exception, getSeverity)
 438 {
 439         zval rv;
 440 
 441         DEFAULT_0_PARAMS;
 442 
 443         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "severity"));
 444 }
 445 /* }}} */
 446 
 447 #define TRACE_APPEND_KEY(key) do {                                          \
 448                 tmp = zend_hash_str_find(ht, key, sizeof(key)-1);                   \
 449                 if (tmp) {                                                          \
 450                         if (Z_TYPE_P(tmp) != IS_STRING) {                               \
 451                                 zend_error(E_WARNING, "Value for %s is no string", key);    \
 452                                 smart_str_appends(str, "[unknown]");                        \
 453                         } else {                                                        \
 454                                 smart_str_appends(str, Z_STRVAL_P(tmp));   \
 455                         }                                                               \
 456                 } \
 457         } while (0)
 458 
 459 /* Windows uses VK_ESCAPE instead of \e */
 460 #ifndef VK_ESCAPE
 461 #define VK_ESCAPE '\e'
 462 #endif
 463 
 464 static size_t compute_escaped_string_len(const char *s, size_t l) {
 465         size_t i, len = l;
 466         for (i = 0; i < l; ++i) {
 467                 char c = s[i];
 468                 if (c == '\n' || c == '\r' || c == '\t' ||
 469                         c == '\f' || c == '\v' || c == '\\' || c == VK_ESCAPE) {
 470                         len += 1;
 471                 } else if (c < 32 || c > 126) {
 472                         len += 3;
 473                 }
 474         }
 475         return len;
 476 }
 477 
 478 static void smart_str_append_escaped(smart_str *str, const char *s, size_t l) {
 479         char *res;
 480         size_t i, len = compute_escaped_string_len(s, l);
 481 
 482         smart_str_alloc(str, len, 0);
 483         res = &ZSTR_VAL(str->s)[ZSTR_LEN(str->s)];
 484         ZSTR_LEN(str->s) += len;
 485 
 486         for (i = 0; i < l; ++i) {
 487                 unsigned char c = s[i];
 488                 if (c < 32 || c == '\\' || c > 126) {
 489                         *res++ = '\\';
 490                         switch (c) {
 491                                 case '\n': *res++ = 'n'; break;
 492                                 case '\r': *res++ = 'r'; break;
 493                                 case '\t': *res++ = 't'; break;
 494                                 case '\f': *res++ = 'f'; break;
 495                                 case '\v': *res++ = 'v'; break;
 496                                 case '\\': *res++ = '\\'; break;
 497                                 case VK_ESCAPE: *res++ = 'e'; break;
 498                                 default:
 499                                         *res++ = 'x';
 500                                         if ((c >> 4) < 10) {
 501                                                 *res++ = (c >> 4) + '0';
 502                                         } else {
 503                                                 *res++ = (c >> 4) + 'A' - 10;
 504                                         }
 505                                         if ((c & 0xf) < 10) {
 506                                                 *res++ = (c & 0xf) + '0';
 507                                         } else {
 508                                                 *res++ = (c & 0xf) + 'A' - 10;
 509                                         }
 510                         }
 511                 } else {
 512                         *res++ = c;
 513                 }
 514         }
 515 }
 516 
 517 static void _build_trace_args(zval *arg, smart_str *str) /* {{{ */
 518 {
 519         /* the trivial way would be to do
 520          * convert_to_string_ex(arg);
 521          * append it and kill the now tmp arg.
 522          * but that could cause some E_NOTICE and also damn long lines.
 523          */
 524 
 525         ZVAL_DEREF(arg);
 526         switch (Z_TYPE_P(arg)) {
 527                 case IS_NULL:
 528                         smart_str_appends(str, "NULL, ");
 529                         break;
 530                 case IS_STRING:
 531                         smart_str_appendc(str, '\'');
 532                         smart_str_append_escaped(str, Z_STRVAL_P(arg), MIN(Z_STRLEN_P(arg), 15));
 533                         if (Z_STRLEN_P(arg) > 15) {
 534                                 smart_str_appends(str, "...', ");
 535                         } else {
 536                                 smart_str_appends(str, "', ");
 537                         }
 538                         break;
 539                 case IS_FALSE:
 540                         smart_str_appends(str, "false, ");
 541                         break;
 542                 case IS_TRUE:
 543                         smart_str_appends(str, "true, ");
 544                         break;
 545                 case IS_RESOURCE:
 546                         smart_str_appends(str, "Resource id #");
 547                         smart_str_append_long(str, Z_RES_HANDLE_P(arg));
 548                         smart_str_appends(str, ", ");
 549                         break;
 550                 case IS_LONG:
 551                         smart_str_append_long(str, Z_LVAL_P(arg));
 552                         smart_str_appends(str, ", ");
 553                         break;
 554                 case IS_DOUBLE: {
 555                         double dval = Z_DVAL_P(arg);
 556                         char *s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
 557                         int l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval);  /* SAFE */
 558                         smart_str_appendl(str, s_tmp, l_tmp);
 559                         smart_str_appends(str, ", ");
 560                         efree(s_tmp);
 561                         break;
 562                 }
 563                 case IS_ARRAY:
 564                         smart_str_appends(str, "Array, ");
 565                         break;
 566                 case IS_OBJECT:
 567                         smart_str_appends(str, "Object(");
 568                         smart_str_appends(str, ZSTR_VAL(Z_OBJCE_P(arg)->name));
 569                         smart_str_appends(str, "), ");
 570                         break;
 571         }
 572 }
 573 /* }}} */
 574 
 575 static void _build_trace_string(smart_str *str, HashTable *ht, uint32_t num) /* {{{ */
 576 {
 577         zval *file, *tmp;
 578 
 579         smart_str_appendc(str, '#');
 580         smart_str_append_long(str, num);
 581         smart_str_appendc(str, ' ');
 582 
 583         file = zend_hash_str_find(ht, "file", sizeof("file")-1);
 584         if (file) {
 585                 if (Z_TYPE_P(file) != IS_STRING) {
 586                         zend_error(E_WARNING, "Function name is no string");
 587                         smart_str_appends(str, "[unknown function]");
 588                 } else{
 589                         zend_long line;
 590                         tmp = zend_hash_str_find(ht, "line", sizeof("line")-1);
 591                         if (tmp) {
 592                                 if (Z_TYPE_P(tmp) == IS_LONG) {
 593                                         line = Z_LVAL_P(tmp);
 594                                 } else {
 595                                         zend_error(E_WARNING, "Line is no long");
 596                                         line = 0;
 597                                 }
 598                         } else {
 599                                 line = 0;
 600                         }
 601                         smart_str_append(str, Z_STR_P(file));
 602                         smart_str_appendc(str, '(');
 603                         smart_str_append_long(str, line);
 604                         smart_str_appends(str, "): ");
 605                 }
 606         } else {
 607                 smart_str_appends(str, "[internal function]: ");
 608         }
 609         TRACE_APPEND_KEY("class");
 610         TRACE_APPEND_KEY("type");
 611         TRACE_APPEND_KEY("function");
 612         smart_str_appendc(str, '(');
 613         tmp = zend_hash_str_find(ht, "args", sizeof("args")-1);
 614         if (tmp) {
 615                 if (Z_TYPE_P(tmp) == IS_ARRAY) {
 616                         size_t last_len = ZSTR_LEN(str->s);
 617                         zval *arg;
 618 
 619                         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(tmp), arg) {
 620                                 _build_trace_args(arg, str);
 621                         } ZEND_HASH_FOREACH_END();
 622 
 623                         if (last_len != ZSTR_LEN(str->s)) {
 624                                 ZSTR_LEN(str->s) -= 2; /* remove last ', ' */
 625                         }
 626                 } else {
 627                         zend_error(E_WARNING, "args element is no array");
 628                 }
 629         }
 630         smart_str_appends(str, ")\n");
 631 }
 632 /* }}} */
 633 
 634 /* {{{ proto string Exception|Error::getTraceAsString()
 635    Obtain the backtrace for the exception as a string (instead of an array) */
 636 ZEND_METHOD(exception, getTraceAsString)
 637 {
 638         zval *trace, *frame, rv;
 639         zend_ulong index;
 640         zval *object;
 641         zend_class_entry *base_ce;
 642         smart_str str = {0};
 643         uint32_t num = 0;
 644 
 645         DEFAULT_0_PARAMS;
 646 
 647         object = getThis();
 648         base_ce = i_get_exception_base(object);
 649 
 650         trace = zend_read_property(base_ce, object, "trace", sizeof("trace")-1, 1, &rv);
 651         if (Z_TYPE_P(trace) != IS_ARRAY) {
 652                 RETURN_FALSE;
 653         }
 654         ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(trace), index, frame) {
 655                 if (Z_TYPE_P(frame) != IS_ARRAY) {
 656                         zend_error(E_WARNING, "Expected array for frame %pu", index);
 657                         continue;
 658                 }
 659 
 660                 _build_trace_string(&str, Z_ARRVAL_P(frame), num++);
 661         } ZEND_HASH_FOREACH_END();
 662 
 663         smart_str_appendc(&str, '#');
 664         smart_str_append_long(&str, num);
 665         smart_str_appends(&str, " {main}");
 666         smart_str_0(&str);
 667 
 668         RETURN_NEW_STR(str.s);
 669 }
 670 /* }}} */
 671 
 672 /* {{{ proto Throwable Exception|Error::getPrevious()
 673    Return previous Throwable or NULL. */
 674 ZEND_METHOD(exception, getPrevious)
 675 {
 676         zval rv;
 677 
 678         DEFAULT_0_PARAMS;
 679 
 680         ZVAL_COPY(return_value, GET_PROPERTY_SILENT(getThis(), "previous"));
 681 } /* }}} */
 682 
 683 size_t zend_spprintf(char **message, size_t max_len, const char *format, ...) /* {{{ */
 684 {
 685         va_list arg;
 686         size_t len;
 687 
 688         va_start(arg, format);
 689         len = zend_vspprintf(message, max_len, format, arg);
 690         va_end(arg);
 691         return len;
 692 }
 693 /* }}} */
 694 
 695 zend_string *zend_strpprintf(size_t max_len, const char *format, ...) /* {{{ */
 696 {
 697         va_list arg;
 698         zend_string *str;
 699 
 700         va_start(arg, format);
 701         str = zend_vstrpprintf(max_len, format, arg);
 702         va_end(arg);
 703         return str;
 704 }
 705 /* }}} */
 706 
 707 /* {{{ proto string Exception|Error::__toString()
 708    Obtain the string representation of the Exception object */
 709 ZEND_METHOD(exception, __toString)
 710 {
 711         zval trace, *exception;
 712         zend_class_entry *base_ce;
 713         zend_string *str;
 714         zend_fcall_info fci;
 715         zval fname, rv;
 716 
 717         DEFAULT_0_PARAMS;
 718 
 719         str = ZSTR_EMPTY_ALLOC();
 720 
 721         exception = getThis();
 722         ZVAL_STRINGL(&fname, "gettraceasstring", sizeof("gettraceasstring")-1);
 723 
 724         while (exception && Z_TYPE_P(exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception), zend_ce_throwable)) {
 725                 zend_string *prev_str = str;
 726                 zend_string *message = zval_get_string(GET_PROPERTY(exception, "message"));
 727                 zend_string *file = zval_get_string(GET_PROPERTY(exception, "file"));
 728                 zend_long line = zval_get_long(GET_PROPERTY(exception, "line"));
 729 
 730                 fci.size = sizeof(fci);
 731                 fci.function_table = &Z_OBJCE_P(exception)->function_table;
 732                 ZVAL_COPY_VALUE(&fci.function_name, &fname);
 733                 fci.symbol_table = NULL;
 734                 fci.object = Z_OBJ_P(exception);
 735                 fci.retval = &trace;
 736                 fci.param_count = 0;
 737                 fci.params = NULL;
 738                 fci.no_separation = 1;
 739 
 740                 zend_call_function(&fci, NULL);
 741 
 742                 if (Z_TYPE(trace) != IS_STRING) {
 743                         zval_ptr_dtor(&trace);
 744                         ZVAL_UNDEF(&trace);
 745                 }
 746 
 747                 if (Z_OBJCE_P(exception) == zend_ce_type_error && strstr(ZSTR_VAL(message), ", called in ")) {
 748                         zend_string *real_message = zend_strpprintf(0, "%s and defined", ZSTR_VAL(message));
 749                         zend_string_release(message);
 750                         message = real_message;
 751                 }
 752 
 753                 if (ZSTR_LEN(message) > 0) {
 754                         str = zend_strpprintf(0, "%s: %s in %s:" ZEND_LONG_FMT
 755                                         "\nStack trace:\n%s%s%s",
 756                                         ZSTR_VAL(Z_OBJCE_P(exception)->name), ZSTR_VAL(message), ZSTR_VAL(file), line,
 757                                         (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n",
 758                                         ZSTR_LEN(prev_str) ? "\n\nNext " : "", ZSTR_VAL(prev_str));
 759                 } else {
 760                         str = zend_strpprintf(0, "%s in %s:" ZEND_LONG_FMT
 761                                         "\nStack trace:\n%s%s%s",
 762                                         ZSTR_VAL(Z_OBJCE_P(exception)->name), ZSTR_VAL(file), line,
 763                                         (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n",
 764                                         ZSTR_LEN(prev_str) ? "\n\nNext " : "", ZSTR_VAL(prev_str));
 765                 }
 766 
 767                 zend_string_release(prev_str);
 768                 zend_string_release(message);
 769                 zend_string_release(file);
 770                 zval_ptr_dtor(&trace);
 771 
 772                 exception = GET_PROPERTY(exception, "previous");
 773         }
 774         zval_dtor(&fname);
 775 
 776         exception = getThis();
 777         base_ce = i_get_exception_base(exception);
 778 
 779         /* We store the result in the private property string so we can access
 780          * the result in uncaught exception handlers without memleaks. */
 781         zend_update_property_str(base_ce, exception, "string", sizeof("string")-1, str);
 782 
 783         RETURN_STR(str);
 784 }
 785 /* }}} */
 786 
 787 /** {{{ Throwable method definition */
 788 const zend_function_entry zend_funcs_throwable[] = {
 789         ZEND_ABSTRACT_ME(throwable, getMessage,       NULL)
 790         ZEND_ABSTRACT_ME(throwable, getCode,          NULL)
 791         ZEND_ABSTRACT_ME(throwable, getFile,          NULL)
 792         ZEND_ABSTRACT_ME(throwable, getLine,          NULL)
 793         ZEND_ABSTRACT_ME(throwable, getTrace,         NULL)
 794         ZEND_ABSTRACT_ME(throwable, getPrevious,      NULL)
 795         ZEND_ABSTRACT_ME(throwable, getTraceAsString, NULL)
 796         ZEND_ABSTRACT_ME(throwable, __toString,       NULL)
 797         ZEND_FE_END
 798 };
 799 /* }}} */
 800 
 801 /* {{{ internal structs */
 802 /* All functions that may be used in uncaught exception handlers must be final
 803  * and must not throw exceptions. Otherwise we would need a facility to handle
 804  * such exceptions in that handler.
 805  * Also all getXY() methods are final because thy serve as read only access to
 806  * their corresponding properties, no more, no less. If after all you need to
 807  * override somthing then it is method __toString().
 808  * And never try to change the state of exceptions and never implement anything
 809  * that gives the user anything to accomplish this.
 810  */
 811 ZEND_BEGIN_ARG_INFO_EX(arginfo_exception___construct, 0, 0, 0)
 812         ZEND_ARG_INFO(0, message)
 813         ZEND_ARG_INFO(0, code)
 814         ZEND_ARG_INFO(0, previous)
 815 ZEND_END_ARG_INFO()
 816 
 817 static const zend_function_entry default_exception_functions[] = {
 818         ZEND_ME(exception, __clone, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
 819         ZEND_ME(exception, __construct, arginfo_exception___construct, ZEND_ACC_PUBLIC)
 820         ZEND_ME(exception, __wakeup, NULL, ZEND_ACC_PUBLIC)
 821         ZEND_ME(exception, getMessage, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
 822         ZEND_ME(exception, getCode, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
 823         ZEND_ME(exception, getFile, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
 824         ZEND_ME(exception, getLine, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
 825         ZEND_ME(exception, getTrace, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
 826         ZEND_ME(exception, getPrevious, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
 827         ZEND_ME(exception, getTraceAsString, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
 828         ZEND_ME(exception, __toString, NULL, 0)
 829         ZEND_FE_END
 830 };
 831 
 832 ZEND_BEGIN_ARG_INFO_EX(arginfo_error_exception___construct, 0, 0, 0)
 833         ZEND_ARG_INFO(0, message)
 834         ZEND_ARG_INFO(0, code)
 835         ZEND_ARG_INFO(0, severity)
 836         ZEND_ARG_INFO(0, filename)
 837         ZEND_ARG_INFO(0, lineno)
 838         ZEND_ARG_INFO(0, previous)
 839 ZEND_END_ARG_INFO()
 840 
 841 static const zend_function_entry error_exception_functions[] = {
 842         ZEND_ME(error_exception, __construct, arginfo_error_exception___construct, ZEND_ACC_PUBLIC)
 843         ZEND_ME(error_exception, getSeverity, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
 844         ZEND_FE_END
 845 };
 846 /* }}} */
 847 
 848 void zend_register_default_exception(void) /* {{{ */
 849 {
 850         zend_class_entry ce;
 851 
 852         REGISTER_MAGIC_INTERFACE(throwable, Throwable);
 853 
 854         memcpy(&default_exception_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
 855         default_exception_handlers.clone_obj = NULL;
 856 
 857         INIT_CLASS_ENTRY(ce, "Exception", default_exception_functions);
 858         zend_ce_exception = zend_register_internal_class_ex(&ce, NULL);
 859         zend_ce_exception->create_object = zend_default_exception_new;
 860         zend_class_implements(zend_ce_exception, 1, zend_ce_throwable);
 861 
 862         zend_declare_property_string(zend_ce_exception, "message", sizeof("message")-1, "", ZEND_ACC_PROTECTED);
 863         zend_declare_property_string(zend_ce_exception, "string", sizeof("string")-1, "", ZEND_ACC_PRIVATE);
 864         zend_declare_property_long(zend_ce_exception, "code", sizeof("code")-1, 0, ZEND_ACC_PROTECTED);
 865         zend_declare_property_null(zend_ce_exception, "file", sizeof("file")-1, ZEND_ACC_PROTECTED);
 866         zend_declare_property_null(zend_ce_exception, "line", sizeof("line")-1, ZEND_ACC_PROTECTED);
 867         zend_declare_property_null(zend_ce_exception, "trace", sizeof("trace")-1, ZEND_ACC_PRIVATE);
 868         zend_declare_property_null(zend_ce_exception, "previous", sizeof("previous")-1, ZEND_ACC_PRIVATE);
 869 
 870         INIT_CLASS_ENTRY(ce, "ErrorException", error_exception_functions);
 871         zend_ce_error_exception = zend_register_internal_class_ex(&ce, zend_ce_exception);
 872         zend_ce_error_exception->create_object = zend_error_exception_new;
 873         zend_declare_property_long(zend_ce_error_exception, "severity", sizeof("severity")-1, E_ERROR, ZEND_ACC_PROTECTED);
 874 
 875         INIT_CLASS_ENTRY(ce, "Error", default_exception_functions);
 876         zend_ce_error = zend_register_internal_class_ex(&ce, NULL);
 877         zend_ce_error->create_object = zend_default_exception_new;
 878         zend_class_implements(zend_ce_error, 1, zend_ce_throwable);
 879 
 880         zend_declare_property_string(zend_ce_error, "message", sizeof("message")-1, "", ZEND_ACC_PROTECTED);
 881         zend_declare_property_string(zend_ce_error, "string", sizeof("string")-1, "", ZEND_ACC_PRIVATE);
 882         zend_declare_property_long(zend_ce_error, "code", sizeof("code")-1, 0, ZEND_ACC_PROTECTED);
 883         zend_declare_property_null(zend_ce_error, "file", sizeof("file")-1, ZEND_ACC_PROTECTED);
 884         zend_declare_property_null(zend_ce_error, "line", sizeof("line")-1, ZEND_ACC_PROTECTED);
 885         zend_declare_property_null(zend_ce_error, "trace", sizeof("trace")-1, ZEND_ACC_PRIVATE);
 886         zend_declare_property_null(zend_ce_error, "previous", sizeof("previous")-1, ZEND_ACC_PRIVATE);
 887 
 888         INIT_CLASS_ENTRY(ce, "ParseError", NULL);
 889         zend_ce_parse_error = zend_register_internal_class_ex(&ce, zend_ce_error);
 890         zend_ce_parse_error->create_object = zend_default_exception_new;
 891 
 892         INIT_CLASS_ENTRY(ce, "TypeError", NULL);
 893         zend_ce_type_error = zend_register_internal_class_ex(&ce, zend_ce_error);
 894         zend_ce_type_error->create_object = zend_default_exception_new;
 895 
 896         INIT_CLASS_ENTRY(ce, "ArithmeticError", NULL);
 897         zend_ce_arithmetic_error = zend_register_internal_class_ex(&ce, zend_ce_error);
 898         zend_ce_arithmetic_error->create_object = zend_default_exception_new;
 899 
 900         INIT_CLASS_ENTRY(ce, "DivisionByZeroError", NULL);
 901         zend_ce_division_by_zero_error = zend_register_internal_class_ex(&ce, zend_ce_arithmetic_error);
 902         zend_ce_division_by_zero_error->create_object = zend_default_exception_new;
 903 }
 904 /* }}} */
 905 
 906 /* {{{ Deprecated - Use zend_ce_exception directly instead */
 907 ZEND_API zend_class_entry *zend_exception_get_default(void)
 908 {
 909         return zend_ce_exception;
 910 }
 911 /* }}} */
 912 
 913 /* {{{ Deprecated - Use zend_ce_error_exception directly instead */
 914 ZEND_API zend_class_entry *zend_get_error_exception(void)
 915 {
 916         return zend_ce_error_exception;
 917 }
 918 /* }}} */
 919 
 920 ZEND_API ZEND_COLD zend_object *zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code) /* {{{ */
 921 {
 922         zval ex;
 923 
 924         if (exception_ce) {
 925                 if (!instanceof_function(exception_ce, zend_ce_throwable)) {
 926                         zend_error(E_NOTICE, "Exceptions must implement Throwable");
 927                         exception_ce = zend_ce_exception;
 928                 }
 929         } else {
 930                 exception_ce = zend_ce_exception;
 931         }
 932         object_init_ex(&ex, exception_ce);
 933 
 934 
 935         if (message) {
 936                 zend_update_property_string(exception_ce, &ex, "message", sizeof("message")-1, message);
 937         }
 938         if (code) {
 939                 zend_update_property_long(exception_ce, &ex, "code", sizeof("code")-1, code);
 940         }
 941 
 942         zend_throw_exception_internal(&ex);
 943         return Z_OBJ(ex);
 944 }
 945 /* }}} */
 946 
 947 ZEND_API ZEND_COLD zend_object *zend_throw_exception_ex(zend_class_entry *exception_ce, zend_long code, const char *format, ...) /* {{{ */
 948 {
 949         va_list arg;
 950         char *message;
 951         zend_object *obj;
 952 
 953         va_start(arg, format);
 954         zend_vspprintf(&message, 0, format, arg);
 955         va_end(arg);
 956         obj = zend_throw_exception(exception_ce, message, code);
 957         efree(message);
 958         return obj;
 959 }
 960 /* }}} */
 961 
 962 ZEND_API ZEND_COLD zend_object *zend_throw_error_exception(zend_class_entry *exception_ce, const char *message, zend_long code, int severity) /* {{{ */
 963 {
 964         zval ex;
 965         zend_object *obj = zend_throw_exception(exception_ce, message, code);
 966         ZVAL_OBJ(&ex, obj);
 967         zend_update_property_long(zend_ce_error_exception, &ex, "severity", sizeof("severity")-1, severity);
 968         return obj;
 969 }
 970 /* }}} */
 971 
 972 static void zend_error_va(int type, const char *file, uint lineno, const char *format, ...) /* {{{ */
 973 {
 974         va_list args;
 975 
 976         va_start(args, format);
 977         zend_error_cb(type, file, lineno, format, args);
 978         va_end(args);
 979 }
 980 /* }}} */
 981 
 982 static void zend_error_helper(int type, const char *filename, const uint lineno, const char *format, ...)
 983 {
 984         va_list va;
 985 
 986         va_start(va, format);
 987         zend_error_cb(type, filename, lineno, format, va);
 988         va_end(va);
 989 }
 990 
 991 /* This function doesn't return if it uses E_ERROR */
 992 ZEND_API ZEND_COLD void zend_exception_error(zend_object *ex, int severity) /* {{{ */
 993 {
 994         zval exception, rv;
 995         zend_class_entry *ce_exception;
 996 
 997         ZVAL_OBJ(&exception, ex);
 998         ce_exception = Z_OBJCE(exception);
 999         EG(exception) = NULL;
1000         if (ce_exception == zend_ce_parse_error) {
1001                 zend_string *message = zval_get_string(GET_PROPERTY(&exception, "message"));
1002                 zend_string *file = zval_get_string(GET_PROPERTY_SILENT(&exception, "file"));
1003                 zend_long line = zval_get_long(GET_PROPERTY_SILENT(&exception, "line"));
1004 
1005                 zend_error_helper(E_PARSE, ZSTR_VAL(file), line, "%s", ZSTR_VAL(message));
1006 
1007                 zend_string_release(file);
1008                 zend_string_release(message);
1009         } else if (instanceof_function(ce_exception, zend_ce_throwable)) {
1010                 zval tmp, rv;
1011                 zend_string *str, *file = NULL;
1012                 zend_long line = 0;
1013 
1014                 zend_call_method_with_0_params(&exception, ce_exception, NULL, "__tostring", &tmp);
1015                 if (!EG(exception)) {
1016                         if (Z_TYPE(tmp) != IS_STRING) {
1017                                 zend_error(E_WARNING, "%s::__toString() must return a string", ZSTR_VAL(ce_exception->name));
1018                         } else {
1019                                 zend_update_property(i_get_exception_base(&exception), &exception, "string", sizeof("string")-1, &tmp);
1020                         }
1021                 }
1022                 zval_ptr_dtor(&tmp);
1023 
1024                 if (EG(exception)) {
1025                         zval zv;
1026 
1027                         ZVAL_OBJ(&zv, EG(exception));
1028                         /* do the best we can to inform about the inner exception */
1029                         if (instanceof_function(ce_exception, zend_ce_exception) || instanceof_function(ce_exception, zend_ce_error)) {
1030                                 file = zval_get_string(GET_PROPERTY_SILENT(&zv, "file"));
1031                                 line = zval_get_long(GET_PROPERTY_SILENT(&zv, "line"));
1032                         }
1033 
1034                         zend_error_va(E_WARNING, (file && ZSTR_LEN(file) > 0) ? ZSTR_VAL(file) : NULL, line,
1035                                 "Uncaught %s in exception handling during call to %s::__tostring()",
1036                                 ZSTR_VAL(Z_OBJCE(zv)->name), ZSTR_VAL(ce_exception->name));
1037 
1038                         if (file) {
1039                                 zend_string_release(file);
1040                         }
1041                 }
1042 
1043                 str = zval_get_string(GET_PROPERTY_SILENT(&exception, "string"));
1044                 file = zval_get_string(GET_PROPERTY_SILENT(&exception, "file"));
1045                 line = zval_get_long(GET_PROPERTY_SILENT(&exception, "line"));
1046 
1047                 zend_error_va(severity, (file && ZSTR_LEN(file) > 0) ? ZSTR_VAL(file) : NULL, line,
1048                         "Uncaught %s\n  thrown", ZSTR_VAL(str));
1049 
1050                 zend_string_release(str);
1051                 zend_string_release(file);
1052         } else {
1053                 zend_error(severity, "Uncaught exception '%s'", ZSTR_VAL(ce_exception->name));
1054         }
1055 
1056         OBJ_RELEASE(ex);
1057 }
1058 /* }}} */
1059 
1060 ZEND_API ZEND_COLD void zend_throw_exception_object(zval *exception) /* {{{ */
1061 {
1062         zend_class_entry *exception_ce;
1063 
1064         if (exception == NULL || Z_TYPE_P(exception) != IS_OBJECT) {
1065                 zend_error_noreturn(E_CORE_ERROR, "Need to supply an object when throwing an exception");
1066         }
1067 
1068         exception_ce = Z_OBJCE_P(exception);
1069 
1070         if (!exception_ce || !instanceof_function(exception_ce, zend_ce_throwable)) {
1071                 zend_throw_error(NULL, "Cannot throw objects that do not implement Throwable");
1072                 return;
1073         }
1074         zend_throw_exception_internal(exception);
1075 }
1076 /* }}} */
1077 
1078 /*
1079  * Local variables:
1080  * tab-width: 4
1081  * c-basic-offset: 4
1082  * indent-tabs-mode: t
1083  * End:
1084  */

/* [<][>][^][v][top][bottom][index][help] */