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: 303 359 84.4 %
Date: 2014-11-22 Functions: 32 35 91.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2014 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             : static zend_class_entry *default_exception_ce;
      34             : static zend_class_entry *error_exception_ce;
      35             : static zend_object_handlers default_exception_handlers;
      36             : ZEND_API void (*zend_throw_exception_hook)(zval *ex TSRMLS_DC);
      37             : 
      38        1273 : void zend_exception_set_previous(zend_object *exception, zend_object *add_previous TSRMLS_DC)
      39             : {
      40             :     zval tmp, *previous, zv, *pzv;
      41             : 
      42        1273 :         if (exception == add_previous || !add_previous || !exception) {
      43        1265 :                 return;
      44             :         }
      45           8 :         ZVAL_OBJ(&tmp, add_previous);
      46           8 :         if (!instanceof_function(Z_OBJCE(tmp), default_exception_ce TSRMLS_CC)) {
      47           0 :                 zend_error(E_ERROR, "Cannot set non exception as previous exception");
      48           0 :                 return;
      49             :         }
      50           8 :         ZVAL_OBJ(&zv, exception);
      51           8 :         pzv = &zv;
      52             :         do {
      53           8 :                 previous = zend_read_property(default_exception_ce, pzv, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
      54           8 :                 if (Z_TYPE_P(previous) == IS_NULL) {
      55           8 :                         zend_update_property(default_exception_ce, pzv, "previous", sizeof("previous")-1, &tmp TSRMLS_CC);
      56           8 :                         GC_REFCOUNT(add_previous)--;
      57           8 :                         return;
      58             :                 }
      59           0 :                 pzv = previous;
      60           0 :         } while (pzv && Z_OBJ_P(pzv) != add_previous);
      61             : }
      62             : 
      63         587 : void zend_exception_save(TSRMLS_D) /* {{{ */
      64             : {
      65         587 :         if (EG(prev_exception)) {
      66           4 :                 zend_exception_set_previous(EG(exception), EG(prev_exception) TSRMLS_CC);
      67             :         }
      68         587 :         if (EG(exception)) {
      69          15 :                 EG(prev_exception) = EG(exception);
      70             :         }
      71         587 :         EG(exception) = NULL;
      72         587 : }
      73             : /* }}} */
      74             : 
      75       20331 : void zend_exception_restore(TSRMLS_D) /* {{{ */
      76             : {
      77       20331 :         if (EG(prev_exception)) {
      78          15 :                 if (EG(exception)) {
      79           3 :                         zend_exception_set_previous(EG(exception), EG(prev_exception) TSRMLS_CC);
      80             :                 } else {
      81          12 :                         EG(exception) = EG(prev_exception);
      82             :                 }
      83          15 :                 EG(prev_exception) = NULL;
      84             :         }
      85       20331 : }
      86             : /* }}} */
      87             : 
      88        2723 : ZEND_API void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */
      89             : {
      90             : #ifdef HAVE_DTRACE
      91             :         if (DTRACE_EXCEPTION_THROWN_ENABLED()) {
      92             :                 if (exception != NULL) {
      93             :                         DTRACE_EXCEPTION_THROWN(Z_OBJ_P(exception)->ce->name->val);
      94             :                 } else {
      95             :                         DTRACE_EXCEPTION_THROWN(NULL);
      96             :                 }
      97             :         }
      98             : #endif /* HAVE_DTRACE */
      99             : 
     100        2723 :         if (exception != NULL) {
     101        1261 :                 zend_object *previous = EG(exception);
     102        1261 :                 zend_exception_set_previous(Z_OBJ_P(exception), EG(exception) TSRMLS_CC);
     103        1261 :                 EG(exception) = Z_OBJ_P(exception);
     104        1261 :                 if (previous) {
     105           0 :                         return;
     106             :                 }
     107             :         }
     108        2723 :         if (!EG(current_execute_data)) {
     109           3 :                 if(EG(exception)) {
     110           3 :                         zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);
     111             :                 }
     112           0 :                 zend_error(E_ERROR, "Exception thrown without a stack frame");
     113             :         }
     114             : 
     115        2720 :         if (zend_throw_exception_hook) {
     116           0 :                 zend_throw_exception_hook(exception TSRMLS_CC);
     117             :         }
     118             : 
     119        7080 :         if (!EG(current_execute_data)->func ||
     120        2715 :             !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
     121        1645 :             (EG(current_execute_data)->opline+1)->opcode == ZEND_HANDLE_EXCEPTION) {
     122             :                 /* no need to rethrow the exception */
     123        1096 :                 return;
     124             :         }
     125        1624 :         EG(opline_before_exception) = EG(current_execute_data)->opline;
     126        1624 :         EG(current_execute_data)->opline = EG(exception_op);
     127             : }
     128             : /* }}} */
     129             : 
     130         101 : ZEND_API void zend_clear_exception(TSRMLS_D) /* {{{ */
     131             : {
     132         101 :         if (EG(prev_exception)) {
     133             :                                 
     134           0 :                 OBJ_RELEASE(EG(prev_exception));
     135           0 :                 EG(prev_exception) = NULL;
     136             :         }
     137         101 :         if (!EG(exception)) {
     138          91 :                 return;
     139             :         }
     140          10 :         OBJ_RELEASE(EG(exception));
     141          10 :         EG(exception) = NULL;
     142          10 :         EG(current_execute_data)->opline = EG(opline_before_exception);
     143             : #if ZEND_DEBUG
     144             :         EG(opline_before_exception) = NULL;
     145             : #endif
     146             : }
     147             : /* }}} */
     148             : 
     149        1677 : static zend_object *zend_default_exception_new_ex(zend_class_entry *class_type, int skip_top_traces TSRMLS_DC) /* {{{ */
     150             : {
     151             :         zval obj;
     152             :         zend_object *object;
     153             :         zval trace;
     154             : 
     155        1677 :         Z_OBJ(obj) = object = zend_objects_new(class_type TSRMLS_CC);
     156        1677 :         Z_OBJ_HT(obj) = &default_exception_handlers;
     157             : 
     158        1677 :         object_properties_init(object, class_type);
     159             : 
     160        1677 :         zend_fetch_debug_backtrace(&trace, skip_top_traces, 0, 0 TSRMLS_CC);
     161             :         Z_SET_REFCOUNT(trace, 0);
     162             : 
     163        1677 :         zend_update_property_string(default_exception_ce, &obj, "file", sizeof("file")-1, zend_get_executed_filename(TSRMLS_C) TSRMLS_CC);
     164        1677 :         zend_update_property_long(default_exception_ce, &obj, "line", sizeof("line")-1, zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC);
     165        1677 :         zend_update_property(default_exception_ce, &obj, "trace", sizeof("trace")-1, &trace TSRMLS_CC);
     166             : 
     167        1677 :         return object;
     168             : }
     169             : /* }}} */
     170             : 
     171        1675 : static zend_object *zend_default_exception_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
     172             : {
     173        1675 :         return zend_default_exception_new_ex(class_type, 0 TSRMLS_CC);
     174             : }
     175             : /* }}} */
     176             : 
     177           2 : static zend_object *zend_error_exception_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
     178             : {
     179           2 :         return zend_default_exception_new_ex(class_type, 2 TSRMLS_CC);
     180             : }
     181             : /* }}} */
     182             : 
     183             : /* {{{ proto Exception Exception::__clone()
     184             :    Clone the exception object */
     185           0 : ZEND_METHOD(exception, __clone)
     186             : {
     187             :         /* Should never be executable */
     188           0 :         zend_throw_exception(NULL, "Cannot clone object using __clone()", 0 TSRMLS_CC);
     189           0 : }
     190             : /* }}} */
     191             : 
     192             : /* {{{ proto Exception::__construct(string message, int code [, Exception previous])
     193             :    Exception constructor */
     194         309 : ZEND_METHOD(exception, __construct)
     195             : {
     196         309 :         zend_string *message = NULL;
     197         309 :         zend_long   code = 0;
     198         309 :         zval  *object, *previous = NULL;
     199         309 :         int    argc = ZEND_NUM_ARGS();
     200             : 
     201         309 :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|SlO!", &message, &code, &previous, default_exception_ce) == FAILURE) {
     202           0 :                 zend_error(E_ERROR, "Wrong parameters for Exception([string $exception [, long $code [, Exception $previous = NULL]]])");
     203             :         }
     204             : 
     205         309 :         object = getThis();
     206             : 
     207         309 :         if (message) {
     208         221 :                 zend_update_property_str(default_exception_ce, object, "message", sizeof("message")-1, message TSRMLS_CC);
     209             :         }
     210             : 
     211         309 :         if (code) {
     212           6 :                 zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code TSRMLS_CC);
     213             :         }
     214             : 
     215         309 :         if (previous) {
     216           3 :                 zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous TSRMLS_CC);
     217             :         }
     218         309 : }
     219             : /* }}} */
     220             : 
     221             : /* {{{ proto ErrorException::__construct(string message, int code, int severity [, string filename [, int lineno [, Exception previous]]])
     222             :    ErrorException constructor */
     223           2 : ZEND_METHOD(error_exception, __construct)
     224             : {
     225           2 :         char  *message = NULL, *filename = NULL;
     226           2 :         zend_long   code = 0, severity = E_ERROR, lineno;
     227           2 :         zval  *object, *previous = NULL;
     228           2 :         int    argc = ZEND_NUM_ARGS();
     229             :         size_t message_len, filename_len;
     230             : 
     231           2 :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|sllslO!", &message, &message_len, &code, &severity, &filename, &filename_len, &lineno, &previous, default_exception_ce) == FAILURE) {
     232           0 :                 zend_error(E_ERROR, "Wrong parameters for ErrorException([string $exception [, long $code, [ long $severity, [ string $filename, [ long $lineno  [, Exception $previous = NULL]]]]]])");
     233             :         }
     234             : 
     235           2 :         object = getThis();
     236             : 
     237           2 :         if (message) {
     238           2 :                 zend_update_property_string(default_exception_ce, object, "message", sizeof("message")-1, message TSRMLS_CC);
     239             :         }
     240             : 
     241           2 :         if (code) {
     242           1 :                 zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code TSRMLS_CC);
     243             :         }
     244             : 
     245           2 :         if (previous) {
     246           0 :                 zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous TSRMLS_CC);
     247             :         }
     248             : 
     249           2 :         zend_update_property_long(default_exception_ce, object, "severity", sizeof("severity")-1, severity TSRMLS_CC);
     250             : 
     251           2 :         if (argc >= 4) {
     252           2 :             zend_update_property_string(default_exception_ce, object, "file", sizeof("file")-1, filename TSRMLS_CC);
     253           2 :         if (argc < 5) {
     254           0 :             lineno = 0; /* invalidate lineno */
     255             :         }
     256           2 :         zend_update_property_long(default_exception_ce, object, "line", sizeof("line")-1, lineno TSRMLS_CC);
     257             :         }
     258           2 : }
     259             : /* }}} */
     260             : 
     261             : #define DEFAULT_0_PARAMS \
     262             :         if (zend_parse_parameters_none() == FAILURE) { \
     263             :                 return; \
     264             :         }
     265             : 
     266             : #define GET_PROPERTY(object, name) \
     267             :         zend_read_property(default_exception_ce, (object), name, sizeof(name) - 1, 0 TSRMLS_CC)
     268             : #define GET_PROPERTY_SILENT(object, name) \
     269             :         zend_read_property(default_exception_ce, (object), name, sizeof(name) - 1, 1 TSRMLS_CC)
     270             : 
     271             : /* {{{ proto string Exception::getFile()
     272             :    Get the file in which the exception occurred */
     273           6 : ZEND_METHOD(exception, getFile)
     274             : {
     275           6 :         DEFAULT_0_PARAMS;
     276             : 
     277           5 :         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "file"));
     278             : }
     279             : /* }}} */
     280             : 
     281             : /* {{{ proto int Exception::getLine()
     282             :    Get the line in which the exception occurred */
     283          13 : ZEND_METHOD(exception, getLine)
     284             : {
     285          13 :         DEFAULT_0_PARAMS;
     286             : 
     287          12 :         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "line"));
     288             : }
     289             : /* }}} */
     290             : 
     291             : /* {{{ proto string Exception::getMessage()
     292             :    Get the exception message */
     293         909 : ZEND_METHOD(exception, getMessage)
     294             : {
     295         909 :         DEFAULT_0_PARAMS;
     296             : 
     297         908 :         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "message"));
     298             : }
     299             : /* }}} */
     300             : 
     301             : /* {{{ proto int Exception::getCode()
     302             :    Get the exception code */
     303          18 : ZEND_METHOD(exception, getCode)
     304             : {
     305          18 :         DEFAULT_0_PARAMS;
     306             : 
     307          17 :         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "code"));
     308             : }
     309             : /* }}} */
     310             : 
     311             : /* {{{ proto array Exception::getTrace()
     312             :    Get the stack trace for the location in which the exception occurred */
     313           6 : ZEND_METHOD(exception, getTrace)
     314             : {
     315           6 :         DEFAULT_0_PARAMS;
     316             : 
     317           5 :         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "trace"));
     318             : }
     319             : /* }}} */
     320             : 
     321             : /* {{{ proto int ErrorException::getSeverity()
     322             :    Get the exception severity */
     323           0 : ZEND_METHOD(error_exception, getSeverity)
     324             : {
     325           0 :         DEFAULT_0_PARAMS;
     326             : 
     327           0 :         ZVAL_COPY(return_value, GET_PROPERTY(getThis(), "severity"));
     328             : }
     329             : /* }}} */
     330             : 
     331             : #define TRACE_APPEND_KEY(key) do {                                          \
     332             :                 tmp = zend_hash_str_find(ht, key, sizeof(key)-1);                   \
     333             :                 if (tmp) {                                                          \
     334             :                         if (Z_TYPE_P(tmp) != IS_STRING) {                               \
     335             :                                 zend_error(E_WARNING, "Value for %s is no string", key);    \
     336             :                                 smart_str_appends(str, "[unknown]");                        \
     337             :                         } else {                                                        \
     338             :                                 smart_str_append(str, Z_STR_P(tmp));   \
     339             :                         }                                                               \
     340             :                 } \
     341             :         } while (0)
     342             : 
     343             : /* Windows uses VK_ESCAPE instead of \e */
     344             : #ifndef VK_ESCAPE
     345             : #define VK_ESCAPE '\e'
     346             : #endif
     347             : 
     348         145 : static size_t compute_escaped_string_len(const char *s, size_t l) {
     349         145 :         size_t i, len = l;
     350        1487 :         for (i = 0; i < l; ++i) {
     351        1342 :                 char c = s[i];
     352        1342 :                 if (c == '\n' || c == '\r' || c == '\t' ||
     353             :                         c == '\f' || c == '\v' || c == '\\' || c == VK_ESCAPE) {
     354           0 :                         len += 1;
     355        1342 :                 } else if (c < 32 || c > 126) {
     356           5 :                         len += 3;
     357             :                 }
     358             :         }
     359         145 :         return len;
     360             : }
     361             : 
     362         145 : static void smart_str_append_escaped(smart_str *str, const char *s, size_t l) {
     363             :         char *res;
     364         145 :         size_t i, len = compute_escaped_string_len(s, l);
     365             : 
     366             :         smart_str_alloc(str, len, 0);
     367         145 :         res = &str->s->val[str->s->len];
     368         145 :         str->s->len += len;
     369             : 
     370        1487 :         for (i = 0; i < l; ++i) {
     371        1342 :                 char c = s[i];
     372        1347 :                 if (c < 32 || c == '\\' || c > 126) {
     373           5 :                         *res++ = '\\';
     374           5 :                         switch (c) {
     375           0 :                                 case '\n': *res++ = 'n'; break;
     376           0 :                                 case '\r': *res++ = 'r'; break;
     377           0 :                                 case '\t': *res++ = 't'; break;
     378           0 :                                 case '\f': *res++ = 'f'; break;
     379           0 :                                 case '\v': *res++ = 'v'; break;
     380           0 :                                 case '\\': *res++ = '\\'; break;
     381           0 :                                 case VK_ESCAPE: *res++ = 'e'; break;
     382             :                                 default:
     383           5 :                                         *res++ = 'x';
     384           5 :                                         if ((c >> 4) < 10) {
     385           5 :                                                 *res++ = (c >> 4) + '0';
     386             :                                         } else {
     387           0 :                                                 *res++ = (c >> 4) + 'A' - 10;
     388             :                                         }
     389           5 :                                         if ((c & 0xf) < 10) {
     390           5 :                                                 *res++ = (c & 0xf) + '0';
     391             :                                         } else {
     392           0 :                                                 *res++ = (c & 0xf) + 'A' - 10;
     393             :                                         }
     394             :                         }
     395             :                 } else {
     396        1337 :                         *res++ = c;
     397             :                 }
     398             :         }
     399         145 : }
     400             : 
     401         242 : static void _build_trace_args(zval *arg, smart_str *str TSRMLS_DC) /* {{{ */
     402             : {
     403             :         /* the trivial way would be to do
     404             :          * convert_to_string_ex(arg);
     405             :          * append it and kill the now tmp arg.
     406             :          * but that could cause some E_NOTICE and also damn long lines.
     407             :          */
     408             : 
     409         242 :         ZVAL_DEREF(arg);
     410         242 :         switch (Z_TYPE_P(arg)) {
     411             :                 case IS_NULL:
     412             :                         smart_str_appends(str, "NULL, ");
     413           0 :                         break;
     414             :                 case IS_STRING:
     415             :                         smart_str_appendc(str, '\'');
     416         145 :                         smart_str_append_escaped(str, Z_STRVAL_P(arg), MIN(Z_STRLEN_P(arg), 15));
     417         145 :                         if (Z_STRLEN_P(arg) > 15) {
     418             :                                 smart_str_appends(str, "...', ");
     419             :                         } else {
     420             :                                 smart_str_appends(str, "', ");
     421             :                         }
     422         145 :                         break;
     423             :                 case IS_FALSE:
     424             :                         smart_str_appends(str, "false, ");
     425           0 :                         break;
     426             :                 case IS_TRUE:
     427             :                         smart_str_appends(str, "true, ");
     428           1 :                         break;
     429             :                 case IS_RESOURCE:
     430             :                         smart_str_appends(str, "Resource id #");
     431           1 :                         smart_str_append_long(str, Z_RES_HANDLE_P(arg));
     432             :                         smart_str_appends(str, ", ");
     433           1 :                         break;
     434             :                 case IS_LONG:
     435          32 :                         smart_str_append_long(str, Z_LVAL_P(arg));
     436             :                         smart_str_appends(str, ", ");
     437          32 :                         break;
     438             :                 case IS_DOUBLE: {
     439           0 :                         double dval = Z_DVAL_P(arg);
     440           0 :                         char *s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
     441           0 :                         int l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval);  /* SAFE */
     442           0 :                         smart_str_appendl(str, s_tmp, l_tmp);
     443             :                         smart_str_appends(str, ", ");
     444           0 :                         efree(s_tmp);
     445           0 :                         break;
     446             :                 }
     447             :                 case IS_ARRAY:
     448             :                         smart_str_appends(str, "Array, ");
     449          41 :                         break;
     450             :                 case IS_OBJECT:
     451             :                         smart_str_appends(str, "Object(");
     452          22 :                         smart_str_append(str, Z_OBJCE_P(arg)->name);
     453             :                         smart_str_appends(str, "), ");
     454             :                         break;
     455             :         }
     456         242 : }
     457             : /* }}} */
     458             : 
     459         179 : static void _build_trace_string(smart_str *str, HashTable *ht, uint32_t num TSRMLS_DC) /* {{{ */
     460             : {
     461             :         zval *file, *tmp;
     462             : 
     463             :         smart_str_appendc(str, '#');
     464         179 :         smart_str_append_long(str, num);
     465             :         smart_str_appendc(str, ' ');
     466             : 
     467         179 :         file = zend_hash_str_find(ht, "file", sizeof("file")-1);
     468         179 :         if (file) {
     469         139 :                 if (Z_TYPE_P(file) != IS_STRING) {
     470           1 :                         zend_error(E_WARNING, "Function name is no string");
     471             :                         smart_str_appends(str, "[unknown function]");
     472             :                 } else{
     473             :                         zend_long line;
     474         138 :                         tmp = zend_hash_str_find(ht, "line", sizeof("line")-1);
     475         138 :                         if (tmp) {
     476         138 :                                 if (Z_TYPE_P(tmp) == IS_LONG) {
     477         138 :                                         line = Z_LVAL_P(tmp);
     478             :                                 } else {
     479           0 :                                         zend_error(E_WARNING, "Line is no long");
     480           0 :                                         line = 0;
     481             :                                 }
     482             :                         } else {
     483           0 :                                 line = 0;
     484             :                         }
     485         138 :                         smart_str_append(str, Z_STR_P(file));
     486             :                         smart_str_appendc(str, '(');
     487             :                         smart_str_append_long(str, line);
     488             :                         smart_str_appends(str, "): ");
     489             :                 }
     490             :         } else {
     491             :                 smart_str_appends(str, "[internal function]: ");
     492             :         }
     493         410 :         TRACE_APPEND_KEY("class");
     494         410 :         TRACE_APPEND_KEY("type");
     495         534 :         TRACE_APPEND_KEY("function");
     496             :         smart_str_appendc(str, '(');
     497         179 :         tmp = zend_hash_str_find(ht, "args", sizeof("args")-1);
     498         179 :         if (tmp) {
     499         177 :                 if (Z_TYPE_P(tmp) == IS_ARRAY) {
     500         176 :                         size_t last_len = str->s->len;
     501             :                         zval *arg;
     502             :                         
     503         660 :                         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(tmp), arg) {
     504         242 :                                 _build_trace_args(arg, str TSRMLS_CC);
     505             :                         } ZEND_HASH_FOREACH_END();
     506             : 
     507         176 :                         if (last_len != str->s->len) {
     508         124 :                                 str->s->len -= 2; /* remove last ', ' */
     509             :                         }
     510             :                 } else {
     511           1 :                         zend_error(E_WARNING, "args element is no array");
     512             :                 }
     513             :         }
     514             :         smart_str_appends(str, ")\n");
     515         179 : }
     516             : /* }}} */
     517             : 
     518             : /* {{{ proto string Exception::getTraceAsString()
     519             :    Obtain the backtrace for the exception as a string (instead of an array) */
     520         150 : ZEND_METHOD(exception, getTraceAsString)
     521             : {
     522             :         zval *trace, *frame;
     523             :         zend_ulong index;
     524         150 :         smart_str str = {0};
     525         150 :         uint32_t num = 0;
     526             : 
     527         150 :         DEFAULT_0_PARAMS;
     528             :         
     529         149 :         trace = zend_read_property(default_exception_ce, getThis(), "trace", sizeof("trace")-1, 1 TSRMLS_CC);
     530         509 :         ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(trace), index, frame) {
     531         180 :                 if (Z_TYPE_P(frame) != IS_ARRAY) {
     532           1 :                         zend_error(E_WARNING, "Expected array for frame %pu", index);
     533           1 :                         continue;
     534             :                 }
     535             : 
     536         179 :                 _build_trace_string(&str, Z_ARRVAL_P(frame), num++ TSRMLS_CC);
     537             :         } ZEND_HASH_FOREACH_END();
     538             : 
     539             :         smart_str_appendc(&str, '#');
     540         149 :         smart_str_append_long(&str, num);
     541             :         smart_str_appends(&str, " {main}");
     542             :         smart_str_0(&str);
     543             : 
     544         149 :         RETURN_NEW_STR(str.s); 
     545             : }
     546             : /* }}} */
     547             : 
     548             : /* {{{ proto string Exception::getPrevious()
     549             :    Return previous Exception or NULL. */
     550           9 : ZEND_METHOD(exception, getPrevious)
     551             : {
     552           9 :         DEFAULT_0_PARAMS;
     553             : 
     554           9 :         ZVAL_COPY(return_value, GET_PROPERTY_SILENT(getThis(), "previous"));
     555             : } /* }}} */
     556             : 
     557        2855 : size_t zend_spprintf(char **message, size_t max_len, const char *format, ...) /* {{{ */
     558             : {
     559             :         va_list arg;
     560             :         size_t len;
     561             : 
     562        2855 :         va_start(arg, format);
     563        2855 :         len = zend_vspprintf(message, max_len, format, arg);
     564        2855 :         va_end(arg);
     565        2855 :         return len;
     566             : }
     567             : /* }}} */
     568             : 
     569        9588 : zend_string *zend_strpprintf(size_t max_len, const char *format, ...) /* {{{ */
     570             : {
     571             :         va_list arg;
     572             :         zend_string *str;
     573             : 
     574        9588 :         va_start(arg, format);
     575        9588 :         str = zend_vstrpprintf(max_len, format, arg);
     576        9588 :         va_end(arg);
     577        9588 :         return str;
     578             : }
     579             : /* }}} */
     580             : 
     581             : /* {{{ proto string Exception::__toString()
     582             :    Obtain the string representation of the Exception object */
     583         138 : ZEND_METHOD(exception, __toString)
     584             : {
     585             :         zval trace, *exception;
     586             :         zend_string *str;
     587             :         zend_fcall_info fci;
     588             :         zval fname;
     589             :         
     590         138 :         DEFAULT_0_PARAMS;
     591             :         
     592         137 :         str = STR_EMPTY_ALLOC();
     593             : 
     594         137 :         exception = getThis();
     595         274 :         ZVAL_STRINGL(&fname, "gettraceasstring", sizeof("gettraceasstring")-1);
     596             : 
     597         697 :         while (exception && Z_TYPE_P(exception) == IS_OBJECT) {
     598         144 :                 zend_string *prev_str = str;
     599         287 :                 zend_string *message = zval_get_string(GET_PROPERTY(exception, "message"));
     600         286 :                 zend_string *file = zval_get_string(GET_PROPERTY(exception, "file"));
     601         286 :                 zend_long line = zval_get_long(GET_PROPERTY(exception, "line"));
     602             : 
     603         143 :                 fci.size = sizeof(fci);
     604         143 :                 fci.function_table = &Z_OBJCE_P(exception)->function_table;
     605         143 :                 ZVAL_COPY_VALUE(&fci.function_name, &fname);
     606         143 :                 fci.symbol_table = NULL;
     607         143 :                 fci.object = Z_OBJ_P(exception);
     608         143 :                 fci.retval = &trace;
     609         143 :                 fci.param_count = 0;
     610         143 :                 fci.params = NULL;
     611         143 :                 fci.no_separation = 1;
     612             : 
     613         143 :                 zend_call_function(&fci, NULL TSRMLS_CC);
     614             : 
     615         143 :                 if (Z_TYPE(trace) != IS_STRING) {
     616           0 :                         zval_ptr_dtor(&trace);
     617           0 :                         ZVAL_UNDEF(&trace);
     618             :                 }
     619             : 
     620         143 :                 if (message->len > 0) {
     621         714 :                         str = zend_strpprintf(0, "exception '%s' with message '%s' in %s:" ZEND_LONG_FMT
     622             :                                         "\nStack trace:\n%s%s%s",
     623         119 :                                         Z_OBJCE_P(exception)->name->val, message->val, file->val, line,
     624         238 :                                         (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n",
     625         119 :                                         prev_str->len ? "\n\nNext " : "", prev_str->val);
     626             :                 } else {
     627         144 :                         str = zend_strpprintf(0, "exception '%s' in %s:" ZEND_LONG_FMT
     628             :                                         "\nStack trace:\n%s%s%s",
     629          24 :                                         Z_OBJCE_P(exception)->name->val, file->val, line,
     630          48 :                                         (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n",
     631          24 :                                         prev_str->len ? "\n\nNext " : "", prev_str->val);
     632             :                 }
     633             : 
     634             :                 zend_string_release(prev_str);
     635             :                 zend_string_release(message);
     636             :                 zend_string_release(file);
     637         143 :                 zval_ptr_dtor(&trace);
     638             : 
     639         143 :                 exception = GET_PROPERTY(exception, "previous");
     640             :         }
     641             :         zval_dtor(&fname);
     642             : 
     643             :         /* We store the result in the private property string so we can access
     644             :          * the result in uncaught exception handlers without memleaks. */
     645         136 :         zend_update_property_str(default_exception_ce, getThis(), "string", sizeof("string")-1, str TSRMLS_CC);
     646             : 
     647         136 :         RETURN_STR(str);
     648             : }
     649             : /* }}} */
     650             : 
     651             : /* {{{ internal structs */
     652             : /* All functions that may be used in uncaught exception handlers must be final
     653             :  * and must not throw exceptions. Otherwise we would need a facility to handle
     654             :  * such exceptions in that handler.
     655             :  * Also all getXY() methods are final because thy serve as read only access to
     656             :  * their corresponding properties, no more, no less. If after all you need to
     657             :  * override somthing then it is method __toString().
     658             :  * And never try to change the state of exceptions and never implement anything
     659             :  * that gives the user anything to accomplish this.
     660             :  */
     661             : ZEND_BEGIN_ARG_INFO_EX(arginfo_exception___construct, 0, 0, 0)
     662             :         ZEND_ARG_INFO(0, message)
     663             :         ZEND_ARG_INFO(0, code)
     664             :         ZEND_ARG_INFO(0, previous)
     665             : ZEND_END_ARG_INFO()
     666             : 
     667             : const static zend_function_entry default_exception_functions[] = {
     668             :         ZEND_ME(exception, __clone, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
     669             :         ZEND_ME(exception, __construct, arginfo_exception___construct, ZEND_ACC_PUBLIC)
     670             :         ZEND_ME(exception, getMessage, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
     671             :         ZEND_ME(exception, getCode, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
     672             :         ZEND_ME(exception, getFile, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
     673             :         ZEND_ME(exception, getLine, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
     674             :         ZEND_ME(exception, getTrace, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
     675             :         ZEND_ME(exception, getPrevious, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
     676             :         ZEND_ME(exception, getTraceAsString, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
     677             :         ZEND_ME(exception, __toString, NULL, 0)
     678             :         {NULL, NULL, NULL}
     679             : };
     680             : 
     681             : ZEND_BEGIN_ARG_INFO_EX(arginfo_error_exception___construct, 0, 0, 0)
     682             :         ZEND_ARG_INFO(0, message)
     683             :         ZEND_ARG_INFO(0, code)
     684             :         ZEND_ARG_INFO(0, severity)
     685             :         ZEND_ARG_INFO(0, filename)
     686             :         ZEND_ARG_INFO(0, lineno)
     687             :         ZEND_ARG_INFO(0, previous)
     688             : ZEND_END_ARG_INFO()
     689             : 
     690             : static const zend_function_entry error_exception_functions[] = {
     691             :         ZEND_ME(error_exception, __construct, arginfo_error_exception___construct, ZEND_ACC_PUBLIC)
     692             :         ZEND_ME(error_exception, getSeverity, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
     693             :         {NULL, NULL, NULL}
     694             : };
     695             : /* }}} */
     696             : 
     697       20507 : void zend_register_default_exception(TSRMLS_D) /* {{{ */
     698             : {
     699             :         zend_class_entry ce;
     700             : 
     701       20507 :         INIT_CLASS_ENTRY(ce, "Exception", default_exception_functions);
     702       20507 :         default_exception_ce = zend_register_internal_class(&ce TSRMLS_CC);
     703       20507 :         default_exception_ce->create_object = zend_default_exception_new;
     704       20507 :         memcpy(&default_exception_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
     705       20507 :         default_exception_handlers.clone_obj = NULL;
     706             : 
     707       20507 :         zend_declare_property_string(default_exception_ce, "message", sizeof("message")-1, "", ZEND_ACC_PROTECTED TSRMLS_CC);
     708       20507 :         zend_declare_property_string(default_exception_ce, "string", sizeof("string")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
     709       20507 :         zend_declare_property_long(default_exception_ce, "code", sizeof("code")-1, 0, ZEND_ACC_PROTECTED TSRMLS_CC);
     710       20507 :         zend_declare_property_null(default_exception_ce, "file", sizeof("file")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
     711       20507 :         zend_declare_property_null(default_exception_ce, "line", sizeof("line")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
     712       20507 :         zend_declare_property_null(default_exception_ce, "trace", sizeof("trace")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
     713       20507 :         zend_declare_property_null(default_exception_ce, "previous", sizeof("previous")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
     714             : 
     715       20507 :         INIT_CLASS_ENTRY(ce, "ErrorException", error_exception_functions);
     716       20507 :         error_exception_ce = zend_register_internal_class_ex(&ce, default_exception_ce TSRMLS_CC);
     717       20507 :         error_exception_ce->create_object = zend_error_exception_new;
     718       20507 :         zend_declare_property_long(error_exception_ce, "severity", sizeof("severity")-1, E_ERROR, ZEND_ACC_PROTECTED TSRMLS_CC);
     719       20507 : }
     720             : /* }}} */
     721             : 
     722      144023 : ZEND_API zend_class_entry *zend_exception_get_default(TSRMLS_D) /* {{{ */
     723             : {
     724      144023 :         return default_exception_ce;
     725             : }
     726             : /* }}} */
     727             : 
     728           0 : ZEND_API zend_class_entry *zend_get_error_exception(TSRMLS_D) /* {{{ */
     729             : {
     730           0 :         return error_exception_ce;
     731             : }
     732             : /* }}} */
     733             : 
     734         890 : ZEND_API zend_object *zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code TSRMLS_DC) /* {{{ */
     735             : {
     736             :         zval ex;
     737             : 
     738         890 :         if (exception_ce) {
     739         761 :                 if (!instanceof_function(exception_ce, default_exception_ce TSRMLS_CC)) {
     740           0 :                         zend_error(E_NOTICE, "Exceptions must be derived from the Exception base class");
     741           0 :                         exception_ce = default_exception_ce;
     742             :                 }
     743             :         } else {
     744         129 :                 exception_ce = default_exception_ce;
     745             :         }
     746         890 :         object_init_ex(&ex, exception_ce);
     747             : 
     748             : 
     749         890 :         if (message) {
     750         890 :                 zend_update_property_string(default_exception_ce, &ex, "message", sizeof("message")-1, message TSRMLS_CC);
     751             :         }
     752         890 :         if (code) {
     753          94 :                 zend_update_property_long(default_exception_ce, &ex, "code", sizeof("code")-1, code TSRMLS_CC);
     754             :         }
     755             : 
     756         890 :         zend_throw_exception_internal(&ex TSRMLS_CC);
     757         890 :         return Z_OBJ(ex);
     758             : }
     759             : /* }}} */
     760             : 
     761         584 : ZEND_API zend_object *zend_throw_exception_ex(zend_class_entry *exception_ce, zend_long code TSRMLS_DC, const char *format, ...) /* {{{ */
     762             : {
     763             :         va_list arg;
     764             :         char *message;
     765             :         zend_object *obj;
     766             : 
     767         584 :         va_start(arg, format);
     768         584 :         zend_vspprintf(&message, 0, format, arg);
     769         584 :         va_end(arg);
     770         584 :         obj = zend_throw_exception(exception_ce, message, code TSRMLS_CC);
     771         584 :         efree(message);
     772         584 :         return obj;
     773             : }
     774             : /* }}} */
     775             : 
     776         144 : ZEND_API zend_object *zend_throw_error_exception(zend_class_entry *exception_ce, const char *message, zend_long code, int severity TSRMLS_DC) /* {{{ */
     777             : {
     778             :         zval ex;
     779         144 :         zend_object *obj = zend_throw_exception(exception_ce, message, code TSRMLS_CC);
     780         144 :         ZVAL_OBJ(&ex, obj);
     781         144 :         zend_update_property_long(default_exception_ce, &ex, "severity", sizeof("severity")-1, severity TSRMLS_CC);
     782         144 :         return obj;
     783             : }
     784             : /* }}} */
     785             : 
     786         109 : static void zend_error_va(int type, const char *file, uint lineno, const char *format, ...) /* {{{ */
     787             : {
     788             :         va_list args;
     789             : 
     790         109 :         va_start(args, format);
     791         109 :         zend_error_cb(type, file, lineno, format, args);
     792           3 :         va_end(args);
     793           3 : }
     794             : /* }}} */
     795             : 
     796             : /* This function doesn't return if it uses E_ERROR */
     797         110 : ZEND_API void zend_exception_error(zend_object *ex, int severity TSRMLS_DC) /* {{{ */
     798             : {
     799             :         zval exception;
     800             :         zend_class_entry *ce_exception;
     801             :         
     802         110 :         ZVAL_OBJ(&exception, ex);
     803         110 :         ce_exception = Z_OBJCE(exception);
     804         110 :         if (instanceof_function(ce_exception, default_exception_ce TSRMLS_CC)) {
     805             :                 zval tmp;
     806         110 :                 zend_string *str, *file = NULL;
     807         110 :                 zend_long line = 0;
     808             : 
     809         110 :                 EG(exception) = NULL;
     810             : 
     811         110 :                 zend_call_method_with_0_params(&exception, ce_exception, NULL, "__tostring", &tmp);
     812         109 :                 if (!EG(exception)) {
     813         109 :                         if (Z_TYPE(tmp) != IS_STRING) {
     814           0 :                                 zend_error(E_WARNING, "%s::__toString() must return a string", ce_exception->name->val);
     815             :                         } else {
     816         109 :                                 zend_update_property_string(default_exception_ce, &exception, "string", sizeof("string")-1, EG(exception) ? ce_exception->name->val : Z_STRVAL(tmp) TSRMLS_CC);
     817             :                         }
     818             :                 }
     819         109 :                 zval_ptr_dtor(&tmp);
     820             : 
     821         109 :                 if (EG(exception)) {
     822             :                         zval zv;
     823             : 
     824           0 :                         ZVAL_OBJ(&zv, EG(exception));
     825             :                         /* do the best we can to inform about the inner exception */
     826           0 :                         if (instanceof_function(ce_exception, default_exception_ce TSRMLS_CC)) {
     827           0 :                                 file = zval_get_string(GET_PROPERTY_SILENT(&zv, "file"));
     828           0 :                                 line = zval_get_long(GET_PROPERTY_SILENT(&zv, "line"));
     829             :                         }
     830             : 
     831           0 :                         zend_error_va(E_WARNING, (file && file->len > 0) ? file->val : NULL, line,
     832             :                                 "Uncaught %s in exception handling during call to %s::__tostring()",
     833           0 :                                 Z_OBJCE(zv)->name->val, ce_exception->name->val);
     834             : 
     835           0 :                         if (file) {
     836             :                                 zend_string_release(file);
     837             :                         }
     838             :                 }
     839             : 
     840         218 :                 str = zval_get_string(GET_PROPERTY_SILENT(&exception, "string"));
     841         218 :                 file = zval_get_string(GET_PROPERTY_SILENT(&exception, "file"));
     842         218 :                 line = zval_get_long(GET_PROPERTY_SILENT(&exception, "line"));
     843             : 
     844         109 :                 zend_error_va(severity, (file && file->len > 0) ? file->val : NULL, line,
     845             :                         "Uncaught %s\n  thrown", str->val);
     846             : 
     847             :                 zend_string_release(str);
     848             :                 zend_string_release(file);
     849             :         } else {
     850           0 :                 zend_error(severity, "Uncaught exception '%s'", ce_exception->name->val);
     851             :         }
     852           3 : }
     853             : /* }}} */
     854             : 
     855         373 : ZEND_API void zend_throw_exception_object(zval *exception TSRMLS_DC) /* {{{ */
     856             : {
     857             :         zend_class_entry *exception_ce;
     858             : 
     859         746 :         if (exception == NULL || Z_TYPE_P(exception) != IS_OBJECT) {
     860           0 :                 zend_error(E_ERROR, "Need to supply an object when throwing an exception");
     861             :         }
     862             : 
     863         373 :         exception_ce = Z_OBJCE_P(exception);
     864             : 
     865         373 :         if (!exception_ce || !instanceof_function(exception_ce, default_exception_ce TSRMLS_CC)) {
     866           2 :                 zend_error(E_ERROR, "Exceptions must be valid objects derived from the Exception base class");
     867             :         }
     868         371 :         zend_throw_exception_internal(exception TSRMLS_CC);
     869         371 : }
     870             : /* }}} */
     871             : 
     872             : /*
     873             :  * Local variables:
     874             :  * tab-width: 4
     875             :  * c-basic-offset: 4
     876             :  * indent-tabs-mode: t
     877             :  * End:
     878             :  */

Generated by: LCOV version 1.10

Generated at Sat, 22 Nov 2014 23:01:11 +0000 (34 hours ago)

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