2 * Create and throw an Ecmascript error object based on a code and a message.
4 * Used when we throw errors internally. Ecmascript generated error objects
5 * are created by Ecmascript code, and the throwing is handled by the bytecode
9 #include "duk_internal.h"
12 * Create and throw an error (originating from Duktape internally)
14 * Push an error object on top of the stack, possibly throw augmenting
15 * the error, and finally longjmp.
17 * If an error occurs while we're dealing with the current error, we might
18 * enter an infinite recursion loop. This is prevented by detecting a
19 * "double fault" through the heap->handling_error flag; the recursion
20 * then stops at the second level.
23 #ifdef DUK_USE_VERBOSE_ERRORS
24 DUK_INTERNAL
void duk_err_create_and_throw(duk_hthread
*thr
, duk_errcode_t code
, const char *msg
, const char *filename
, duk_int_t line
) {
26 DUK_INTERNAL
void duk_err_create_and_throw(duk_hthread
*thr
, duk_errcode_t code
) {
28 duk_context
*ctx
= (duk_context
*) thr
;
29 duk_bool_t double_error
= thr
->heap
->handling_error
;
31 #ifdef DUK_USE_VERBOSE_ERRORS
32 DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld",
33 (long) code
, (const char *) msg
,
34 (const char *) filename
, (long) line
));
36 DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld", (long) code
));
39 DUK_ASSERT(thr
!= NULL
);
40 DUK_ASSERT(ctx
!= NULL
);
42 thr
->heap
->handling_error
= 1;
45 /* Allow headroom for calls during error handling (see GH-191).
46 * We allow space for 10 additional recursions, with one extra
47 * for, e.g. a print() call at the deepest level.
49 DUK_ASSERT(thr
->callstack_max
== DUK_CALLSTACK_DEFAULT_MAX
);
50 thr
->callstack_max
= DUK_CALLSTACK_DEFAULT_MAX
+ DUK_CALLSTACK_GROW_STEP
+ 11;
53 DUK_ASSERT(thr
->callstack_max
== DUK_CALLSTACK_DEFAULT_MAX
+ DUK_CALLSTACK_GROW_STEP
+ 11); /* just making sure */
55 /* Sync so that augmentation sees up-to-date activations, NULL
56 * thr->ptr_curr_pc so that it's not used if side effects occur
57 * in augmentation or longjmp handling.
59 duk_hthread_sync_and_null_currpc(thr
);
62 * Create and push an error object onto the top of stack.
63 * If a "double error" occurs, use a fixed error instance
64 * to avoid further trouble.
67 /* XXX: if attempt to push beyond allocated valstack, this double fault
68 * handling fails miserably. We should really write the double error
69 * directly to thr->heap->lj.value1 and avoid valstack use entirely.
73 if (thr
->builtins
[DUK_BIDX_DOUBLE_ERROR
]) {
74 DUK_D(DUK_DPRINT("double fault detected -> push built-in fixed 'double error' instance"));
75 duk_push_hobject_bidx(ctx
, DUK_BIDX_DOUBLE_ERROR
);
77 DUK_D(DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance "
78 "-> push the error code as a number"));
79 duk_push_int(ctx
, (duk_int_t
) code
);
82 /* Error object is augmented at its creation here. */
83 duk_require_stack(ctx
, 1);
84 /* XXX: unnecessary '%s' formatting here, but cannot use
85 * 'msg' as a format string directly.
87 #ifdef DUK_USE_VERBOSE_ERRORS
88 duk_push_error_object_raw(ctx
,
89 code
| DUK_ERRCODE_FLAG_NOBLAME_FILELINE
,
95 duk_push_error_object_raw(ctx
,
96 code
| DUK_ERRCODE_FLAG_NOBLAME_FILELINE
,
104 * Augment error (throw time), unless alloc/double error
107 if (double_error
|| code
== DUK_ERR_ALLOC_ERROR
) {
108 DUK_D(DUK_DPRINT("alloc or double error: skip throw augmenting to avoid further trouble"));
110 #if defined(DUK_USE_AUGMENT_ERROR_THROW)
111 DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)",
112 (duk_tval
*) duk_get_tval(ctx
, -1)));
113 duk_err_augment_error_throw(thr
);
121 duk_err_setup_heap_ljstate(thr
, DUK_LJ_TYPE_THROW
);
123 thr
->callstack_max
= DUK_CALLSTACK_DEFAULT_MAX
; /* reset callstack limit */
124 thr
->heap
->handling_error
= 0;
126 DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)",
127 (duk_tval
*) &thr
->heap
->lj
.value1
, (duk_tval
*) &thr
->heap
->lj
.value2
));
129 duk_err_longjmp(thr
);
134 * Helper for C function call negative return values.
137 DUK_INTERNAL
void duk_error_throw_from_negative_rc(duk_hthread
*thr
, duk_ret_t rc
) {
138 duk_context
*ctx
= (duk_context
*) thr
;
142 DUK_ASSERT(thr
!= NULL
);
145 /* XXX: this generates quite large code - perhaps select the error
146 * class based on the code and then just use the error 'name'?
148 /* XXX: shared strings */
153 case DUK_RET_UNIMPLEMENTED_ERROR
: msg
= "unimplemented"; break;
154 case DUK_RET_UNSUPPORTED_ERROR
: msg
= "unsupported"; break;
155 case DUK_RET_INTERNAL_ERROR
: msg
= "internal"; break;
156 case DUK_RET_ALLOC_ERROR
: msg
= "alloc"; break;
157 case DUK_RET_ASSERTION_ERROR
: msg
= "assertion"; break;
158 case DUK_RET_API_ERROR
: msg
= "api"; break;
159 case DUK_RET_UNCAUGHT_ERROR
: msg
= "uncaught"; break;
160 case DUK_RET_ERROR
: msg
= "error"; break;
161 case DUK_RET_EVAL_ERROR
: msg
= "eval"; break;
162 case DUK_RET_RANGE_ERROR
: msg
= "range"; break;
163 case DUK_RET_REFERENCE_ERROR
: msg
= "reference"; break;
164 case DUK_RET_SYNTAX_ERROR
: msg
= "syntax"; break;
165 case DUK_RET_TYPE_ERROR
: msg
= "type"; break;
166 case DUK_RET_URI_ERROR
: msg
= "uri"; break;
167 default: msg
= "unknown"; break;
170 DUK_ASSERT(msg
!= NULL
);
173 * The __FILE__ and __LINE__ information is intentionally not used in the
174 * creation of the error object, as it isn't useful in the tracedata. The
175 * tracedata still contains the function which returned the negative return
176 * code, and having the file/line of this function isn't very useful.
179 duk_error_raw(ctx
, code
, NULL
, 0, "%s error (rc %ld)", (const char *) msg
, (long) rc
);