PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - Zend - zend_exceptions.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 393 440 89.3 %
Date: 2015-08-29 Functions: 35 40 87.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 29 Aug 2015 10:22:10 +0000 (29 hours ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.