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