This source file includes following definitions.
- zend_exception_set_previous
- zend_exception_save
- zend_exception_restore
- zend_throw_exception_internal
- zend_clear_exception
- zend_default_exception_new_ex
- zend_default_exception_new
- zend_error_exception_new
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- _default_exception_get_entry
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- _build_trace_args
- _build_trace_string
- ZEND_METHOD
- ZEND_METHOD
- zend_spprintf
- ZEND_METHOD
- zend_register_default_exception
- zend_exception_get_default
- zend_get_error_exception
- zend_throw_exception
- zend_throw_exception_ex
- zend_throw_error_exception
- zend_error_va
- zend_exception_error
- zend_throw_exception_object
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
32 static zend_class_entry *default_exception_ce;
33 static zend_class_entry *error_exception_ce;
34 static zend_object_handlers default_exception_handlers;
35 ZEND_API void (*zend_throw_exception_hook)(zval *ex TSRMLS_DC);
36
37 void zend_exception_set_previous(zval *exception, zval *add_previous TSRMLS_DC)
38 {
39 zval *previous, *ancestor;
40
41 if (exception == add_previous || !add_previous || !exception) {
42 return;
43 }
44 if (Z_TYPE_P(add_previous) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(add_previous), default_exception_ce TSRMLS_CC)) {
45 zend_error(E_ERROR, "Cannot set non exception as previous exception");
46 return;
47 }
48 while (exception && exception != add_previous && Z_OBJ_HANDLE_P(exception) != Z_OBJ_HANDLE_P(add_previous)) {
49 ancestor = zend_read_property(default_exception_ce, add_previous, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
50 while (Z_TYPE_P(ancestor) == IS_OBJECT) {
51 if (Z_OBJ_HANDLE_P(ancestor) == Z_OBJ_HANDLE_P(exception)) {
52 zval_ptr_dtor(&add_previous);
53 return;
54 }
55 ancestor = zend_read_property(default_exception_ce, ancestor, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
56 }
57 previous = zend_read_property(default_exception_ce, exception, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
58 if (Z_TYPE_P(previous) == IS_NULL) {
59 zend_update_property(default_exception_ce, exception, "previous", sizeof("previous")-1, add_previous TSRMLS_CC);
60 Z_DELREF_P(add_previous);
61 return;
62 }
63 exception = previous;
64 }
65 }
66
67 void zend_exception_save(TSRMLS_D)
68 {
69 if (EG(prev_exception)) {
70 zend_exception_set_previous(EG(exception), EG(prev_exception) TSRMLS_CC);
71 }
72 if (EG(exception)) {
73 EG(prev_exception) = EG(exception);
74 }
75 EG(exception) = NULL;
76 }
77
78
79 void zend_exception_restore(TSRMLS_D)
80 {
81 if (EG(prev_exception)) {
82 if (EG(exception)) {
83 zend_exception_set_previous(EG(exception), EG(prev_exception) TSRMLS_CC);
84 } else {
85 EG(exception) = EG(prev_exception);
86 }
87 EG(prev_exception) = NULL;
88 }
89 }
90
91
92 void zend_throw_exception_internal(zval *exception TSRMLS_DC)
93 {
94 #ifdef HAVE_DTRACE
95 if (DTRACE_EXCEPTION_THROWN_ENABLED()) {
96 const char *classname;
97 zend_uint name_len;
98
99 if (exception != NULL) {
100 zend_get_object_classname(exception, &classname, &name_len TSRMLS_CC);
101 DTRACE_EXCEPTION_THROWN((char *)classname);
102 } else {
103 DTRACE_EXCEPTION_THROWN(NULL);
104 }
105 }
106 #endif
107
108 if (exception != NULL) {
109 zval *previous = EG(exception);
110 zend_exception_set_previous(exception, EG(exception) TSRMLS_CC);
111 EG(exception) = exception;
112 if (previous) {
113 return;
114 }
115 }
116 if (!EG(current_execute_data)) {
117 if(EG(exception)) {
118 zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);
119 }
120 zend_error(E_ERROR, "Exception thrown without a stack frame");
121 }
122
123 if (zend_throw_exception_hook) {
124 zend_throw_exception_hook(exception TSRMLS_CC);
125 }
126
127 if (EG(current_execute_data)->opline == NULL ||
128 (EG(current_execute_data)->opline+1)->opcode == ZEND_HANDLE_EXCEPTION) {
129
130 return;
131 }
132 EG(opline_before_exception) = EG(current_execute_data)->opline;
133 EG(current_execute_data)->opline = EG(exception_op);
134 }
135
136
137 ZEND_API void zend_clear_exception(TSRMLS_D)
138 {
139 if (EG(prev_exception)) {
140 zval_ptr_dtor(&EG(prev_exception));
141 EG(prev_exception) = NULL;
142 }
143 if (!EG(exception)) {
144 return;
145 }
146 zval_ptr_dtor(&EG(exception));
147 EG(exception) = NULL;
148 EG(current_execute_data)->opline = EG(opline_before_exception);
149 #if ZEND_DEBUG
150 EG(opline_before_exception) = NULL;
151 #endif
152 }
153
154
155 static zend_object_value zend_default_exception_new_ex(zend_class_entry *class_type, int skip_top_traces TSRMLS_DC)
156 {
157 zval obj;
158 zend_object *object;
159 zval *trace;
160
161 Z_OBJVAL(obj) = zend_objects_new(&object, class_type TSRMLS_CC);
162 Z_OBJ_HT(obj) = &default_exception_handlers;
163
164 object_properties_init(object, class_type);
165
166 ALLOC_ZVAL(trace);
167 Z_UNSET_ISREF_P(trace);
168 Z_SET_REFCOUNT_P(trace, 0);
169 zend_fetch_debug_backtrace(trace, skip_top_traces, 0, 0 TSRMLS_CC);
170
171 zend_update_property_string(default_exception_ce, &obj, "file", sizeof("file")-1, zend_get_executed_filename(TSRMLS_C) TSRMLS_CC);
172 zend_update_property_long(default_exception_ce, &obj, "line", sizeof("line")-1, zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC);
173 zend_update_property(default_exception_ce, &obj, "trace", sizeof("trace")-1, trace TSRMLS_CC);
174
175 return Z_OBJVAL(obj);
176 }
177
178
179 static zend_object_value zend_default_exception_new(zend_class_entry *class_type TSRMLS_DC)
180 {
181 return zend_default_exception_new_ex(class_type, 0 TSRMLS_CC);
182 }
183
184
185 static zend_object_value zend_error_exception_new(zend_class_entry *class_type TSRMLS_DC)
186 {
187 return zend_default_exception_new_ex(class_type, 2 TSRMLS_CC);
188 }
189
190
191
192
193 ZEND_METHOD(exception, __clone)
194 {
195
196 zend_throw_exception(NULL, "Cannot clone object using __clone()", 0 TSRMLS_CC);
197 }
198
199
200
201
202 ZEND_METHOD(exception, __construct)
203 {
204 char *message = NULL;
205 long code = 0;
206 zval *object, *previous = NULL;
207 int argc = ZEND_NUM_ARGS(), message_len;
208
209 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|slO!", &message, &message_len, &code, &previous, default_exception_ce) == FAILURE) {
210 zend_error(E_ERROR, "Wrong parameters for Exception([string $exception [, long $code [, Exception $previous = NULL]]])");
211 }
212
213 object = getThis();
214
215 if (message) {
216 zend_update_property_stringl(default_exception_ce, object, "message", sizeof("message")-1, message, message_len TSRMLS_CC);
217 }
218
219 if (code) {
220 zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code TSRMLS_CC);
221 }
222
223 if (previous) {
224 zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous TSRMLS_CC);
225 }
226 }
227
228
229
230
231 #define CHECK_EXC_TYPE(name, type) \
232 value = zend_read_property(default_exception_ce, object, name, sizeof(name)-1, 0 TSRMLS_CC); \
233 if(value && Z_TYPE_P(value) != type) { \
234 zval *tmp; \
235 MAKE_STD_ZVAL(tmp); \
236 ZVAL_STRINGL(tmp, name, sizeof(name)-1, 1); \
237 Z_OBJ_HANDLER_P(object, unset_property)(object, tmp, 0 TSRMLS_CC); \
238 zval_ptr_dtor(&tmp); \
239 }
240
241 ZEND_METHOD(exception, __wakeup)
242 {
243 zval *value;
244 zval *object = getThis();
245 CHECK_EXC_TYPE("message", IS_STRING);
246 CHECK_EXC_TYPE("string", IS_STRING);
247 CHECK_EXC_TYPE("code", IS_LONG);
248 CHECK_EXC_TYPE("file", IS_STRING);
249 CHECK_EXC_TYPE("line", IS_LONG);
250 CHECK_EXC_TYPE("trace", IS_ARRAY);
251 CHECK_EXC_TYPE("previous", IS_OBJECT);
252 }
253
254
255
256
257 ZEND_METHOD(error_exception, __construct)
258 {
259 char *message = NULL, *filename = NULL;
260 long code = 0, severity = E_ERROR, lineno;
261 zval *object, *previous = NULL;
262 int argc = ZEND_NUM_ARGS(), message_len, filename_len;
263
264 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) {
265 zend_error(E_ERROR, "Wrong parameters for ErrorException([string $exception [, long $code, [ long $severity, [ string $filename, [ long $lineno [, Exception $previous = NULL]]]]]])");
266 }
267
268 object = getThis();
269
270 if (message) {
271 zend_update_property_string(default_exception_ce, object, "message", sizeof("message")-1, message TSRMLS_CC);
272 }
273
274 if (code) {
275 zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code TSRMLS_CC);
276 }
277
278 if (previous) {
279 zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous TSRMLS_CC);
280 }
281
282 zend_update_property_long(default_exception_ce, object, "severity", sizeof("severity")-1, severity TSRMLS_CC);
283
284 if (argc >= 4) {
285 zend_update_property_string(default_exception_ce, object, "file", sizeof("file")-1, filename TSRMLS_CC);
286 if (argc < 5) {
287 lineno = 0;
288 }
289 zend_update_property_long(default_exception_ce, object, "line", sizeof("line")-1, lineno TSRMLS_CC);
290 }
291 }
292
293
294 #define DEFAULT_0_PARAMS \
295 if (zend_parse_parameters_none() == FAILURE) { \
296 return; \
297 }
298
299 static void _default_exception_get_entry(zval *object, char *name, int name_len, zval *return_value TSRMLS_DC)
300 {
301 zval *value;
302
303 value = zend_read_property(default_exception_ce, object, name, name_len, 0 TSRMLS_CC);
304
305 *return_value = *value;
306 zval_copy_ctor(return_value);
307 INIT_PZVAL(return_value);
308 }
309
310
311
312
313 ZEND_METHOD(exception, getFile)
314 {
315 DEFAULT_0_PARAMS;
316
317 _default_exception_get_entry(getThis(), "file", sizeof("file")-1, return_value TSRMLS_CC);
318 }
319
320
321
322
323 ZEND_METHOD(exception, getLine)
324 {
325 DEFAULT_0_PARAMS;
326
327 _default_exception_get_entry(getThis(), "line", sizeof("line")-1, return_value TSRMLS_CC);
328 }
329
330
331
332
333 ZEND_METHOD(exception, getMessage)
334 {
335 DEFAULT_0_PARAMS;
336
337 _default_exception_get_entry(getThis(), "message", sizeof("message")-1, return_value TSRMLS_CC);
338 }
339
340
341
342
343 ZEND_METHOD(exception, getCode)
344 {
345 DEFAULT_0_PARAMS;
346
347 _default_exception_get_entry(getThis(), "code", sizeof("code")-1, return_value TSRMLS_CC);
348 }
349
350
351
352
353 ZEND_METHOD(exception, getTrace)
354 {
355 DEFAULT_0_PARAMS;
356
357 _default_exception_get_entry(getThis(), "trace", sizeof("trace")-1, return_value TSRMLS_CC);
358 }
359
360
361
362
363 ZEND_METHOD(error_exception, getSeverity)
364 {
365 DEFAULT_0_PARAMS;
366
367 _default_exception_get_entry(getThis(), "severity", sizeof("severity")-1, return_value TSRMLS_CC);
368 }
369
370
371
372 #define TRACE_APPEND_CHR(chr) \
373 *str = (char*)erealloc(*str, *len + 1 + 1); \
374 (*str)[(*len)++] = chr
375
376 #define TRACE_APPEND_STRL(val, vallen) \
377 { \
378 int l = vallen; \
379 *str = (char*)erealloc(*str, *len + l + 1); \
380 memcpy((*str) + *len, val, l); \
381 *len += l; \
382 }
383
384 #define TRACE_APPEND_STR(val) \
385 TRACE_APPEND_STRL(val, sizeof(val)-1)
386
387 #define TRACE_APPEND_KEY(key) \
388 if (zend_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
389 if (Z_TYPE_PP(tmp) != IS_STRING) { \
390 zend_error(E_WARNING, "Value for %s is no string", key); \
391 TRACE_APPEND_STR("[unknown]"); \
392 } else { \
393 TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \
394 } \
395 }
396
397
398 #define TRACE_ARG_APPEND(vallen) \
399 *str = (char*)erealloc(*str, *len + 1 + vallen); \
400 memmove((*str) + *len - l_added + 1 + vallen, (*str) + *len - l_added + 1, l_added);
401
402
403
404 static int _build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
405 {
406 char **str;
407 int *len;
408
409 str = va_arg(args, char**);
410 len = va_arg(args, int*);
411
412
413
414
415
416
417
418 switch (Z_TYPE_PP(arg)) {
419 case IS_NULL:
420 TRACE_APPEND_STR("NULL, ");
421 break;
422 case IS_STRING: {
423 int l_added;
424 TRACE_APPEND_CHR('\'');
425 if (Z_STRLEN_PP(arg) > 15) {
426 TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
427 TRACE_APPEND_STR("...', ");
428 l_added = 15 + 6 + 1;
429 } else {
430 l_added = Z_STRLEN_PP(arg);
431 TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
432 TRACE_APPEND_STR("', ");
433 l_added += 3 + 1;
434 }
435 while (--l_added) {
436 unsigned char chr = (*str)[*len - l_added];
437 if (chr < 32 || chr == '\\' || chr > 126) {
438 (*str)[*len - l_added] = '\\';
439
440 switch (chr) {
441 case '\n':
442 TRACE_ARG_APPEND(1);
443 (*str)[++(*len) - l_added] = 'n';
444 break;
445 case '\r':
446 TRACE_ARG_APPEND(1);
447 (*str)[++(*len) - l_added] = 'r';
448 break;
449 case '\t':
450 TRACE_ARG_APPEND(1);
451 (*str)[++(*len) - l_added] = 't';
452 break;
453 case '\f':
454 TRACE_ARG_APPEND(1);
455 (*str)[++(*len) - l_added] = 'f';
456 break;
457 case '\v':
458 TRACE_ARG_APPEND(1);
459 (*str)[++(*len) - l_added] = 'v';
460 break;
461 #ifndef PHP_WIN32
462 case '\e':
463 #else
464 case VK_ESCAPE:
465 #endif
466 TRACE_ARG_APPEND(1);
467 (*str)[++(*len) - l_added] = 'e';
468 break;
469 case '\\':
470 TRACE_ARG_APPEND(1);
471 (*str)[++(*len) - l_added] = '\\';
472 break;
473 default:
474 TRACE_ARG_APPEND(3);
475 (*str)[*len - l_added + 1] = 'x';
476 if ((chr >> 4) < 10) {
477 (*str)[*len - l_added + 2] = (chr >> 4) + '0';
478 } else {
479 (*str)[*len - l_added + 2] = (chr >> 4) + 'A' - 10;
480 }
481 if (chr % 16 < 10) {
482 (*str)[*len - l_added + 3] = chr % 16 + '0';
483 } else {
484 (*str)[*len - l_added + 3] = chr % 16 + 'A' - 10;
485 }
486 *len += 3;
487 }
488 }
489 }
490 break;
491 }
492 case IS_BOOL:
493 if (Z_LVAL_PP(arg)) {
494 TRACE_APPEND_STR("true, ");
495 } else {
496 TRACE_APPEND_STR("false, ");
497 }
498 break;
499 case IS_RESOURCE:
500 TRACE_APPEND_STR("Resource id #");
501
502 case IS_LONG: {
503 long lval = Z_LVAL_PP(arg);
504 char s_tmp[MAX_LENGTH_OF_LONG + 1];
505 int l_tmp = zend_sprintf(s_tmp, "%ld", lval);
506 TRACE_APPEND_STRL(s_tmp, l_tmp);
507 TRACE_APPEND_STR(", ");
508 break;
509 }
510 case IS_DOUBLE: {
511 double dval = Z_DVAL_PP(arg);
512 char *s_tmp;
513 int l_tmp;
514
515 s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
516 l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval);
517 TRACE_APPEND_STRL(s_tmp, l_tmp);
518
519 efree(s_tmp);
520 TRACE_APPEND_STR(", ");
521 break;
522 }
523 case IS_ARRAY:
524 TRACE_APPEND_STR("Array, ");
525 break;
526 case IS_OBJECT: {
527 const char *class_name;
528 zend_uint class_name_len;
529 int dup;
530
531 TRACE_APPEND_STR("Object(");
532
533 dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
534
535 TRACE_APPEND_STRL(class_name, class_name_len);
536 if(!dup) {
537 efree((char*)class_name);
538 }
539
540 TRACE_APPEND_STR("), ");
541 break;
542 }
543 default:
544 break;
545 }
546 return ZEND_HASH_APPLY_KEEP;
547 }
548
549
550 static int _build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
551 {
552 char *s_tmp, **str;
553 int *len, *num;
554 long line;
555 HashTable *ht = Z_ARRVAL_PP(frame);
556 zval **file, **tmp;
557
558 if (Z_TYPE_PP(frame) != IS_ARRAY) {
559 zend_error(E_WARNING, "Expected array for frame %lu", hash_key->h);
560 return ZEND_HASH_APPLY_KEEP;
561 }
562
563 str = va_arg(args, char**);
564 len = va_arg(args, int*);
565 num = va_arg(args, int*);
566
567 s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
568 sprintf(s_tmp, "#%d ", (*num)++);
569 TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
570 efree(s_tmp);
571 if (zend_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
572 if (Z_TYPE_PP(file) != IS_STRING) {
573 zend_error(E_WARNING, "Function name is no string");
574 TRACE_APPEND_STR("[unknown function]");
575 } else{
576 if (zend_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
577 if (Z_TYPE_PP(tmp) == IS_LONG) {
578 line = Z_LVAL_PP(tmp);
579 } else {
580 zend_error(E_WARNING, "Line is no long");
581 line = 0;
582 }
583 } else {
584 line = 0;
585 }
586 s_tmp = emalloc(Z_STRLEN_PP(file) + MAX_LENGTH_OF_LONG + 4 + 1);
587 sprintf(s_tmp, "%s(%ld): ", Z_STRVAL_PP(file), line);
588 TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
589 efree(s_tmp);
590 }
591 } else {
592 TRACE_APPEND_STR("[internal function]: ");
593 }
594 TRACE_APPEND_KEY("class");
595 TRACE_APPEND_KEY("type");
596 TRACE_APPEND_KEY("function");
597 TRACE_APPEND_CHR('(');
598 if (zend_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
599 if (Z_TYPE_PP(tmp) == IS_ARRAY) {
600 int last_len = *len;
601 zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)_build_trace_args, 2, str, len);
602 if (last_len != *len) {
603 *len -= 2;
604 }
605 } else {
606 zend_error(E_WARNING, "args element is no array");
607 }
608 }
609 TRACE_APPEND_STR(")\n");
610 return ZEND_HASH_APPLY_KEEP;
611 }
612
613
614
615
616 ZEND_METHOD(exception, getTraceAsString)
617 {
618 zval *trace;
619 char *res, **str, *s_tmp;
620 int res_len = 0, *len = &res_len, num = 0;
621
622 DEFAULT_0_PARAMS;
623
624 trace = zend_read_property(default_exception_ce, getThis(), "trace", sizeof("trace")-1, 1 TSRMLS_CC);
625 if (Z_TYPE_P(trace) != IS_ARRAY) {
626 RETURN_FALSE;
627 }
628
629 res = estrdup("");
630 str = &res;
631
632 zend_hash_apply_with_arguments(Z_ARRVAL_P(trace) TSRMLS_CC, (apply_func_args_t)_build_trace_string, 3, str, len, &num);
633
634 s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 7 + 1);
635 sprintf(s_tmp, "#%d {main}", num);
636 TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
637 efree(s_tmp);
638
639 res[res_len] = '\0';
640 RETURN_STRINGL(res, res_len, 0);
641 }
642
643
644
645
646 ZEND_METHOD(exception, getPrevious)
647 {
648 zval *previous;
649
650 DEFAULT_0_PARAMS;
651
652 previous = zend_read_property(default_exception_ce, getThis(), "previous", sizeof("previous")-1, 1 TSRMLS_CC);
653 RETURN_ZVAL(previous, 1, 0);
654 }
655
656
657 int zend_spprintf(char **message, int max_len, const char *format, ...)
658 {
659 va_list arg;
660 int len;
661
662 va_start(arg, format);
663 len = zend_vspprintf(message, max_len, format, arg);
664 va_end(arg);
665 return len;
666 }
667
668
669
670
671 ZEND_METHOD(exception, __toString)
672 {
673 zval message, file, line, *trace, *exception;
674 char *str, *prev_str;
675 int len = 0;
676 zend_fcall_info fci;
677 zval fname;
678
679 DEFAULT_0_PARAMS;
680
681 str = estrndup("", 0);
682
683 exception = getThis();
684 ZVAL_STRINGL(&fname, "gettraceasstring", sizeof("gettraceasstring")-1, 1);
685
686 while (exception && Z_TYPE_P(exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception), default_exception_ce TSRMLS_CC)) {
687 prev_str = str;
688 _default_exception_get_entry(exception, "message", sizeof("message")-1, &message TSRMLS_CC);
689 _default_exception_get_entry(exception, "file", sizeof("file")-1, &file TSRMLS_CC);
690 _default_exception_get_entry(exception, "line", sizeof("line")-1, &line TSRMLS_CC);
691
692 convert_to_string(&message);
693 convert_to_string(&file);
694 convert_to_long(&line);
695
696 trace = NULL;
697 fci.size = sizeof(fci);
698 fci.function_table = &Z_OBJCE_P(exception)->function_table;
699 fci.function_name = &fname;
700 fci.symbol_table = NULL;
701 fci.object_ptr = exception;
702 fci.retval_ptr_ptr = &trace;
703 fci.param_count = 0;
704 fci.params = NULL;
705 fci.no_separation = 1;
706
707 zend_call_function(&fci, NULL TSRMLS_CC);
708
709 if (trace && Z_TYPE_P(trace) != IS_STRING) {
710 zval_ptr_dtor(&trace);
711 trace = NULL;
712 }
713
714 if (Z_STRLEN(message) > 0) {
715 len = zend_spprintf(&str, 0, "exception '%s' with message '%s' in %s:%ld\nStack trace:\n%s%s%s",
716 Z_OBJCE_P(exception)->name, Z_STRVAL(message), Z_STRVAL(file), Z_LVAL(line),
717 (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n",
718 len ? "\n\nNext " : "", prev_str);
719 } else {
720 len = zend_spprintf(&str, 0, "exception '%s' in %s:%ld\nStack trace:\n%s%s%s",
721 Z_OBJCE_P(exception)->name, Z_STRVAL(file), Z_LVAL(line),
722 (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n",
723 len ? "\n\nNext " : "", prev_str);
724 }
725 efree(prev_str);
726 zval_dtor(&message);
727 zval_dtor(&file);
728 zval_dtor(&line);
729
730 exception = zend_read_property(default_exception_ce, exception, "previous", sizeof("previous")-1, 0 TSRMLS_CC);
731
732 if (trace) {
733 zval_ptr_dtor(&trace);
734 }
735
736 }
737 zval_dtor(&fname);
738
739
740
741 zend_update_property_string(default_exception_ce, getThis(), "string", sizeof("string")-1, str TSRMLS_CC);
742
743 RETURN_STRINGL(str, len, 0);
744 }
745
746
747
748
749
750
751
752
753
754
755
756
757 ZEND_BEGIN_ARG_INFO_EX(arginfo_exception___construct, 0, 0, 0)
758 ZEND_ARG_INFO(0, message)
759 ZEND_ARG_INFO(0, code)
760 ZEND_ARG_INFO(0, previous)
761 ZEND_END_ARG_INFO()
762
763 const static zend_function_entry default_exception_functions[] = {
764 ZEND_ME(exception, __clone, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
765 ZEND_ME(exception, __construct, arginfo_exception___construct, ZEND_ACC_PUBLIC)
766 ZEND_ME(exception, __wakeup, NULL, ZEND_ACC_PUBLIC)
767 ZEND_ME(exception, getMessage, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
768 ZEND_ME(exception, getCode, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
769 ZEND_ME(exception, getFile, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
770 ZEND_ME(exception, getLine, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
771 ZEND_ME(exception, getTrace, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
772 ZEND_ME(exception, getPrevious, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
773 ZEND_ME(exception, getTraceAsString, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
774 ZEND_ME(exception, __toString, NULL, 0)
775 {NULL, NULL, NULL}
776 };
777
778 ZEND_BEGIN_ARG_INFO_EX(arginfo_error_exception___construct, 0, 0, 0)
779 ZEND_ARG_INFO(0, message)
780 ZEND_ARG_INFO(0, code)
781 ZEND_ARG_INFO(0, severity)
782 ZEND_ARG_INFO(0, filename)
783 ZEND_ARG_INFO(0, lineno)
784 ZEND_ARG_INFO(0, previous)
785 ZEND_END_ARG_INFO()
786
787 static const zend_function_entry error_exception_functions[] = {
788 ZEND_ME(error_exception, __construct, arginfo_error_exception___construct, ZEND_ACC_PUBLIC)
789 ZEND_ME(error_exception, getSeverity, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
790 {NULL, NULL, NULL}
791 };
792
793
794 void zend_register_default_exception(TSRMLS_D)
795 {
796 zend_class_entry ce;
797
798 INIT_CLASS_ENTRY(ce, "Exception", default_exception_functions);
799 default_exception_ce = zend_register_internal_class(&ce TSRMLS_CC);
800 default_exception_ce->create_object = zend_default_exception_new;
801 memcpy(&default_exception_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
802 default_exception_handlers.clone_obj = NULL;
803
804 zend_declare_property_string(default_exception_ce, "message", sizeof("message")-1, "", ZEND_ACC_PROTECTED TSRMLS_CC);
805 zend_declare_property_string(default_exception_ce, "string", sizeof("string")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
806 zend_declare_property_long(default_exception_ce, "code", sizeof("code")-1, 0, ZEND_ACC_PROTECTED TSRMLS_CC);
807 zend_declare_property_null(default_exception_ce, "file", sizeof("file")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
808 zend_declare_property_null(default_exception_ce, "line", sizeof("line")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
809 zend_declare_property_null(default_exception_ce, "trace", sizeof("trace")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
810 zend_declare_property_null(default_exception_ce, "previous", sizeof("previous")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
811
812 INIT_CLASS_ENTRY(ce, "ErrorException", error_exception_functions);
813 error_exception_ce = zend_register_internal_class_ex(&ce, default_exception_ce, NULL TSRMLS_CC);
814 error_exception_ce->create_object = zend_error_exception_new;
815 zend_declare_property_long(error_exception_ce, "severity", sizeof("severity")-1, E_ERROR, ZEND_ACC_PROTECTED TSRMLS_CC);
816 }
817
818
819 ZEND_API zend_class_entry *zend_exception_get_default(TSRMLS_D)
820 {
821 return default_exception_ce;
822 }
823
824
825 ZEND_API zend_class_entry *zend_get_error_exception(TSRMLS_D)
826 {
827 return error_exception_ce;
828 }
829
830
831 ZEND_API zval * zend_throw_exception(zend_class_entry *exception_ce, const char *message, long code TSRMLS_DC)
832 {
833 zval *ex;
834
835 MAKE_STD_ZVAL(ex);
836 if (exception_ce) {
837 if (!instanceof_function(exception_ce, default_exception_ce TSRMLS_CC)) {
838 zend_error(E_NOTICE, "Exceptions must be derived from the Exception base class");
839 exception_ce = default_exception_ce;
840 }
841 } else {
842 exception_ce = default_exception_ce;
843 }
844 object_init_ex(ex, exception_ce);
845
846
847 if (message) {
848 zend_update_property_string(default_exception_ce, ex, "message", sizeof("message")-1, message TSRMLS_CC);
849 }
850 if (code) {
851 zend_update_property_long(default_exception_ce, ex, "code", sizeof("code")-1, code TSRMLS_CC);
852 }
853
854 zend_throw_exception_internal(ex TSRMLS_CC);
855 return ex;
856 }
857
858
859 ZEND_API zval * zend_throw_exception_ex(zend_class_entry *exception_ce, long code TSRMLS_DC, const char *format, ...)
860 {
861 va_list arg;
862 char *message;
863 zval *zexception;
864
865 va_start(arg, format);
866 zend_vspprintf(&message, 0, format, arg);
867 va_end(arg);
868 zexception = zend_throw_exception(exception_ce, message, code TSRMLS_CC);
869 efree(message);
870 return zexception;
871 }
872
873
874 ZEND_API zval * zend_throw_error_exception(zend_class_entry *exception_ce, const char *message, long code, int severity TSRMLS_DC)
875 {
876 zval *ex = zend_throw_exception(exception_ce, message, code TSRMLS_CC);
877 zend_update_property_long(default_exception_ce, ex, "severity", sizeof("severity")-1, severity TSRMLS_CC);
878 return ex;
879 }
880
881
882 static void zend_error_va(int type, const char *file, uint lineno, const char *format, ...)
883 {
884 va_list args;
885
886 va_start(args, format);
887 zend_error_cb(type, file, lineno, format, args);
888 va_end(args);
889 }
890
891
892
893 ZEND_API void zend_exception_error(zval *exception, int severity TSRMLS_DC)
894 {
895 zend_class_entry *ce_exception = Z_OBJCE_P(exception);
896 if (instanceof_function(ce_exception, default_exception_ce TSRMLS_CC)) {
897 zval *str, *file, *line;
898
899 EG(exception) = NULL;
900
901 zend_call_method_with_0_params(&exception, ce_exception, NULL, "__tostring", &str);
902 if (!EG(exception)) {
903 if (Z_TYPE_P(str) != IS_STRING) {
904 zend_error(E_WARNING, "%s::__toString() must return a string", ce_exception->name);
905 } else {
906 zend_update_property_string(default_exception_ce, exception, "string", sizeof("string")-1, EG(exception) ? ce_exception->name : Z_STRVAL_P(str) TSRMLS_CC);
907 }
908 }
909 zval_ptr_dtor(&str);
910
911 if (EG(exception)) {
912
913 if (instanceof_function(ce_exception, default_exception_ce TSRMLS_CC)) {
914 file = zend_read_property(default_exception_ce, EG(exception), "file", sizeof("file")-1, 1 TSRMLS_CC);
915 line = zend_read_property(default_exception_ce, EG(exception), "line", sizeof("line")-1, 1 TSRMLS_CC);
916
917 convert_to_string(file);
918 file = (Z_STRLEN_P(file) > 0) ? file : NULL;
919 line = (Z_TYPE_P(line) == IS_LONG) ? line : NULL;
920 } else {
921 file = NULL;
922 line = NULL;
923 }
924 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);
925 }
926
927 str = zend_read_property(default_exception_ce, exception, "string", sizeof("string")-1, 1 TSRMLS_CC);
928 file = zend_read_property(default_exception_ce, exception, "file", sizeof("file")-1, 1 TSRMLS_CC);
929 line = zend_read_property(default_exception_ce, exception, "line", sizeof("line")-1, 1 TSRMLS_CC);
930
931 convert_to_string(str);
932 convert_to_string(file);
933 convert_to_long(line);
934
935 zend_error_va(severity, (Z_STRLEN_P(file) > 0) ? Z_STRVAL_P(file) : NULL, Z_LVAL_P(line), "Uncaught %s\n thrown", Z_STRVAL_P(str));
936 } else {
937 zend_error(severity, "Uncaught exception '%s'", ce_exception->name);
938 }
939 }
940
941
942 ZEND_API void zend_throw_exception_object(zval *exception TSRMLS_DC)
943 {
944 zend_class_entry *exception_ce;
945
946 if (exception == NULL || Z_TYPE_P(exception) != IS_OBJECT) {
947 zend_error(E_ERROR, "Need to supply an object when throwing an exception");
948 }
949
950 exception_ce = Z_OBJCE_P(exception);
951
952 if (!exception_ce || !instanceof_function(exception_ce, default_exception_ce TSRMLS_CC)) {
953 zend_error(E_ERROR, "Exceptions must be valid objects derived from the Exception base class");
954 }
955 zend_throw_exception_internal(exception TSRMLS_CC);
956 }
957
958
959
960
961
962
963
964
965