1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 * JS standard exception implementation.
13 #include "mozilla/ArrayUtils.h"
14 #include "mozilla/PodOperations.h"
27 #include "jswrapper.h"
29 #include "gc/Marking.h"
30 #include "vm/ErrorObject.h"
31 #include "vm/GlobalObject.h"
32 #include "vm/StringBuffer.h"
34 #include "jsobjinlines.h"
36 #include "vm/ErrorObject-inl.h"
39 using namespace js::gc
;
40 using namespace js::types
;
42 using mozilla::ArrayLength
;
43 using mozilla::PodArrayZero
;
46 exn_finalize(FreeOp
* fop
, JSObject
* obj
);
49 Error(JSContext
* cx
, unsigned argc
, Value
* vp
);
52 exn_toSource(JSContext
* cx
, unsigned argc
, Value
* vp
);
54 static const JSFunctionSpec exception_methods
[] = {
56 JS_FN(js_toSource_str
, exn_toSource
, 0, 0),
58 JS_SELF_HOSTED_FN(js_toString_str
, "ErrorToString", 0,0),
62 #define IMPLEMENT_ERROR_SUBCLASS(name) \
64 js_Error_str, /* yes, really */ \
65 JSCLASS_IMPLEMENTS_BARRIERS | \
66 JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
67 JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS), \
68 nullptr, /* addProperty */ \
69 nullptr, /* delProperty */ \
70 nullptr, /* getProperty */ \
71 nullptr, /* setProperty */ \
72 nullptr, /* enumerate */ \
73 nullptr, /* resolve */ \
74 nullptr, /* convert */ \
77 nullptr, /* hasInstance */ \
78 nullptr, /* construct */ \
79 nullptr, /* trace */ \
81 ErrorObject::createConstructor, \
82 ErrorObject::createProto, \
92 ErrorObject::classes
[JSEXN_LIMIT
] = {
95 JSCLASS_IMPLEMENTS_BARRIERS
|
96 JSCLASS_HAS_CACHED_PROTO(JSProto_Error
) |
97 JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS
),
98 nullptr, /* addProperty */
99 nullptr, /* delProperty */
100 nullptr, /* getProperty */
101 nullptr, /* setProperty */
102 nullptr, /* enumerate */
103 nullptr, /* resolve */
104 nullptr, /* convert */
107 nullptr, /* hasInstance */
108 nullptr, /* construct */
111 ErrorObject::createConstructor
,
112 ErrorObject::createProto
,
118 IMPLEMENT_ERROR_SUBCLASS(InternalError
),
119 IMPLEMENT_ERROR_SUBCLASS(EvalError
),
120 IMPLEMENT_ERROR_SUBCLASS(RangeError
),
121 IMPLEMENT_ERROR_SUBCLASS(ReferenceError
),
122 IMPLEMENT_ERROR_SUBCLASS(SyntaxError
),
123 IMPLEMENT_ERROR_SUBCLASS(TypeError
),
124 IMPLEMENT_ERROR_SUBCLASS(URIError
)
128 js::CopyErrorReport(JSContext
* cx
, JSErrorReport
* report
)
131 * We use a single malloc block to make a deep copy of JSErrorReport with
132 * the following layout:
134 * array of copies of report->messageArgs
135 * char16_t array with characters for all messageArgs
136 * char16_t array with characters for ucmessage
137 * char16_t array with characters for uclinebuf and uctokenptr
138 * char array with characters for linebuf and tokenptr
139 * char array with characters for filename
140 * Such layout together with the properties enforced by the following
141 * asserts does not need any extra alignment padding.
143 JS_STATIC_ASSERT(sizeof(JSErrorReport
) % sizeof(const char*) == 0);
144 JS_STATIC_ASSERT(sizeof(const char*) % sizeof(char16_t
) == 0);
148 size_t uclinebufSize
;
149 size_t ucmessageSize
;
150 size_t i
, argsArraySize
, argsCopySize
, argSize
;
155 #define JS_CHARS_SIZE(chars) ((js_strlen(chars) + 1) * sizeof(char16_t))
157 filenameSize
= report
->filename
? strlen(report
->filename
) + 1 : 0;
158 linebufSize
= report
->linebuf
? strlen(report
->linebuf
) + 1 : 0;
159 uclinebufSize
= report
->uclinebuf
? JS_CHARS_SIZE(report
->uclinebuf
) : 0;
163 if (report
->ucmessage
) {
164 ucmessageSize
= JS_CHARS_SIZE(report
->ucmessage
);
165 if (report
->messageArgs
) {
166 for (i
= 0; report
->messageArgs
[i
]; ++i
)
167 argsCopySize
+= JS_CHARS_SIZE(report
->messageArgs
[i
]);
169 /* Non-null messageArgs should have at least one non-null arg. */
171 argsArraySize
= (i
+ 1) * sizeof(const char16_t
*);
176 * The mallocSize can not overflow since it represents the sum of the
177 * sizes of already allocated objects.
179 mallocSize
= sizeof(JSErrorReport
) + argsArraySize
+ argsCopySize
+
180 ucmessageSize
+ uclinebufSize
+ linebufSize
+ filenameSize
;
181 cursor
= cx
->pod_malloc
<uint8_t>(mallocSize
);
185 copy
= (JSErrorReport
*)cursor
;
186 memset(cursor
, 0, sizeof(JSErrorReport
));
187 cursor
+= sizeof(JSErrorReport
);
189 if (argsArraySize
!= 0) {
190 copy
->messageArgs
= (const char16_t
**)cursor
;
191 cursor
+= argsArraySize
;
192 for (i
= 0; report
->messageArgs
[i
]; ++i
) {
193 copy
->messageArgs
[i
] = (const char16_t
*)cursor
;
194 argSize
= JS_CHARS_SIZE(report
->messageArgs
[i
]);
195 js_memcpy(cursor
, report
->messageArgs
[i
], argSize
);
198 copy
->messageArgs
[i
] = nullptr;
199 MOZ_ASSERT(cursor
== (uint8_t*)copy
->messageArgs
[0] + argsCopySize
);
202 if (report
->ucmessage
) {
203 copy
->ucmessage
= (const char16_t
*)cursor
;
204 js_memcpy(cursor
, report
->ucmessage
, ucmessageSize
);
205 cursor
+= ucmessageSize
;
208 if (report
->uclinebuf
) {
209 copy
->uclinebuf
= (const char16_t
*)cursor
;
210 js_memcpy(cursor
, report
->uclinebuf
, uclinebufSize
);
211 cursor
+= uclinebufSize
;
212 if (report
->uctokenptr
) {
213 copy
->uctokenptr
= copy
->uclinebuf
+ (report
->uctokenptr
-
218 if (report
->linebuf
) {
219 copy
->linebuf
= (const char*)cursor
;
220 js_memcpy(cursor
, report
->linebuf
, linebufSize
);
221 cursor
+= linebufSize
;
222 if (report
->tokenptr
) {
223 copy
->tokenptr
= copy
->linebuf
+ (report
->tokenptr
-
228 if (report
->filename
) {
229 copy
->filename
= (const char*)cursor
;
230 js_memcpy(cursor
, report
->filename
, filenameSize
);
232 MOZ_ASSERT(cursor
+ filenameSize
== (uint8_t*)copy
+ mallocSize
);
234 /* Copy non-pointer members. */
235 copy
->isMuted
= report
->isMuted
;
236 copy
->lineno
= report
->lineno
;
237 copy
->column
= report
->column
;
238 copy
->errorNumber
= report
->errorNumber
;
239 copy
->exnType
= report
->exnType
;
241 /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */
242 copy
->flags
= report
->flags
;
248 struct SuppressErrorsGuard
251 JSErrorReporter prevReporter
;
252 JS::AutoSaveExceptionState prevState
;
254 explicit SuppressErrorsGuard(JSContext
* cx
)
256 prevReporter(JS_SetErrorReporter(cx
->runtime(), nullptr)),
260 ~SuppressErrorsGuard()
262 JS_SetErrorReporter(cx
->runtime(), prevReporter
);
267 js::ComputeStackString(JSContext
* cx
)
273 SuppressErrorsGuard
seg(cx
);
274 for (NonBuiltinFrameIter
i(cx
, FrameIter::ALL_CONTEXTS
, FrameIter::GO_THROUGH_SAVED
,
275 cx
->compartment()->principals
);
279 /* First append the function name, if any. */
280 if (i
.isNonEvalFunctionFrame())
281 atom
= i
.functionDisplayAtom();
284 if (atom
&& !sb
.append(atom
))
287 /* Next a @ separating function name from source location. */
291 /* Now the filename. */
293 /* First, try the `//# sourceURL=some-display-url.js` directive. */
294 if (const char16_t
* display
= i
.scriptDisplayURL()) {
295 if (!sb
.append(display
, js_strlen(display
)))
298 /* Second, try the actual filename. */
299 else if (const char* filename
= i
.scriptFilename()) {
300 if (!sb
.append(filename
, strlen(filename
)))
305 uint32_t line
= i
.computeLine(&column
);
306 // Now the line number
307 if (!sb
.append(':') || !NumberValueToStringBuffer(cx
, NumberValue(line
), sb
))
310 // Finally, : followed by the column number (1-based, as in other browsers)
312 if (!sb
.append(':') || !NumberValueToStringBuffer(cx
, NumberValue(column
+ 1), sb
) ||
319 * Cut off the stack if it gets too deep (most commonly for
320 * infinite recursion errors).
322 const size_t MaxReportedStackDepth
= 1u << 20;
323 if (sb
.length() > MaxReportedStackDepth
)
328 return sb
.finishString();
332 exn_finalize(FreeOp
* fop
, JSObject
* obj
)
334 if (JSErrorReport
* report
= obj
->as
<ErrorObject
>().getErrorReport())
339 js_ErrorFromException(JSContext
* cx
, HandleObject objArg
)
341 // It's ok to UncheckedUnwrap here, since all we do is get the
342 // JSErrorReport, and consumers are careful with the information they get
343 // from that anyway. Anyone doing things that would expose anything in the
344 // JSErrorReport to page script either does a security check on the
345 // JSErrorReport's principal or also tries to do toString on our object and
346 // will fail if they can't unwrap it.
347 RootedObject
obj(cx
, UncheckedUnwrap(objArg
));
348 if (!obj
->is
<ErrorObject
>())
351 return obj
->as
<ErrorObject
>().getOrCreateErrorReport(cx
);
355 Error(JSContext
* cx
, unsigned argc
, Value
* vp
)
357 CallArgs args
= CallArgsFromVp(argc
, vp
);
359 /* Compute the error message, if any. */
360 RootedString
message(cx
, nullptr);
361 if (args
.hasDefined(0)) {
362 message
= ToString
<CanGC
>(cx
, args
[0]);
367 /* Find the scripted caller. */
368 NonBuiltinFrameIter
iter(cx
);
370 /* Set the 'fileName' property. */
371 RootedString
fileName(cx
);
372 if (args
.length() > 1) {
373 fileName
= ToString
<CanGC
>(cx
, args
[1]);
375 fileName
= cx
->runtime()->emptyString
;
377 if (const char* cfilename
= iter
.scriptFilename())
378 fileName
= JS_NewStringCopyZ(cx
, cfilename
);
384 /* Set the 'lineNumber' property. */
385 uint32_t lineNumber
, columnNumber
= 0;
386 if (args
.length() > 2) {
387 if (!ToUint32(cx
, args
[2], &lineNumber
))
390 lineNumber
= iter
.done() ? 0 : iter
.computeLine(&columnNumber
);
393 Rooted
<JSString
*> stack(cx
, ComputeStackString(cx
));
398 * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
399 * called as functions, without operator new. But as we do not give
400 * each constructor a distinct JSClass, we must get the exception type
403 JSExnType exnType
= JSExnType(args
.callee().as
<JSFunction
>().getExtendedSlot(0).toInt32());
405 RootedObject
obj(cx
, ErrorObject::create(cx
, exnType
, stack
, fileName
,
406 lineNumber
, columnNumber
, nullptr, message
));
410 args
.rval().setObject(*obj
);
416 * Return a string that may eval to something similar to the original object.
419 exn_toSource(JSContext
* cx
, unsigned argc
, Value
* vp
)
421 JS_CHECK_RECURSION(cx
, return false);
422 CallArgs args
= CallArgsFromVp(argc
, vp
);
424 RootedObject
obj(cx
, ToObject(cx
, args
.thisv()));
428 RootedValue
nameVal(cx
);
429 RootedString
name(cx
);
430 if (!JSObject::getProperty(cx
, obj
, obj
, cx
->names().name
, &nameVal
) ||
431 !(name
= ToString
<CanGC
>(cx
, nameVal
)))
436 RootedValue
messageVal(cx
);
437 RootedString
message(cx
);
438 if (!JSObject::getProperty(cx
, obj
, obj
, cx
->names().message
, &messageVal
) ||
439 !(message
= ValueToSource(cx
, messageVal
)))
444 RootedValue
filenameVal(cx
);
445 RootedString
filename(cx
);
446 if (!JSObject::getProperty(cx
, obj
, obj
, cx
->names().fileName
, &filenameVal
) ||
447 !(filename
= ValueToSource(cx
, filenameVal
)))
452 RootedValue
linenoVal(cx
);
454 if (!JSObject::getProperty(cx
, obj
, obj
, cx
->names().lineNumber
, &linenoVal
) ||
455 !ToUint32(cx
, linenoVal
, &lineno
))
461 if (!sb
.append("(new ") || !sb
.append(name
) || !sb
.append("("))
464 if (!sb
.append(message
))
467 if (!filename
->empty()) {
468 if (!sb
.append(", ") || !sb
.append(filename
))
472 /* We have a line, but no filename, add empty string */
473 if (filename
->empty() && !sb
.append(", \"\""))
476 JSString
* linenumber
= ToString
<CanGC
>(cx
, linenoVal
);
479 if (!sb
.append(", ") || !sb
.append(linenumber
))
483 if (!sb
.append("))"))
486 JSString
* str
= sb
.finishString();
489 args
.rval().setString(str
);
494 /* static */ JSObject
*
495 ErrorObject::createProto(JSContext
* cx
, JSProtoKey key
)
497 RootedObject
errorProto(cx
, GenericCreatePrototype(cx
, key
));
501 Rooted
<ErrorObject
*> err(cx
, &errorProto
->as
<ErrorObject
>());
502 RootedString
emptyStr(cx
, cx
->names().empty
);
503 JSExnType type
= ExnTypeFromProtoKey(key
);
504 if (!ErrorObject::init(cx
, err
, type
, nullptr, emptyStr
, emptyStr
, 0, 0, emptyStr
))
507 // The various prototypes also have .name in addition to the normal error
508 // instance properties.
509 RootedPropertyName
name(cx
, ClassName(key
, cx
));
510 RootedValue
nameValue(cx
, StringValue(name
));
511 if (!JSObject::defineProperty(cx
, err
, cx
->names().name
, nameValue
, nullptr, nullptr, 0))
517 /* static */ JSObject
*
518 ErrorObject::createConstructor(JSContext
* cx
, JSProtoKey key
)
520 RootedObject
ctor(cx
);
521 ctor
= GenericCreateConstructor
<Error
, 1, JSFunction::ExtendedFinalizeKind
>(cx
, key
);
525 ctor
->as
<JSFunction
>().setExtendedSlot(0, Int32Value(ExnTypeFromProtoKey(key
)));
529 JS_FRIEND_API(JSFlatString
*)
530 js::GetErrorTypeName(JSRuntime
* rt
, int16_t exnType
)
533 * JSEXN_INTERNALERR returns null to prevent that "InternalError: "
534 * is prepended before "uncaught exception: "
536 if (exnType
<= JSEXN_NONE
|| exnType
>= JSEXN_LIMIT
||
537 exnType
== JSEXN_INTERNALERR
)
541 JSProtoKey key
= GetExceptionProtoKey(JSExnType(exnType
));
542 return ClassName(key
, rt
);
546 js_ErrorToException(JSContext
* cx
, const char* message
, JSErrorReport
* reportp
,
547 JSErrorCallback callback
, void* userRef
)
549 // Tell our caller to report immediately if this report is just a warning.
551 if (JSREPORT_IS_WARNING(reportp
->flags
))
554 // Find the exception index associated with this error.
555 JSErrNum errorNumber
= static_cast<JSErrNum
>(reportp
->errorNumber
);
557 callback
= js_GetErrorMessage
;
558 const JSErrorFormatString
* errorString
= callback(userRef
, errorNumber
);
559 JSExnType exnType
= errorString
? static_cast<JSExnType
>(errorString
->exnType
) : JSEXN_NONE
;
560 MOZ_ASSERT(exnType
< JSEXN_LIMIT
);
562 // Return false (no exception raised) if no exception is associated
563 // with the given error number.
564 if (exnType
== JSEXN_NONE
)
567 // Prevent infinite recursion.
568 if (cx
->generatingError
)
570 AutoScopedAssign
<bool> asa(&cx
->generatingError
, true);
572 // Create an exception object.
573 RootedString
messageStr(cx
, reportp
->ucmessage
? JS_NewUCStringCopyZ(cx
, reportp
->ucmessage
)
574 : JS_NewStringCopyZ(cx
, message
));
576 return cx
->isExceptionPending();
578 RootedString
fileName(cx
, JS_NewStringCopyZ(cx
, reportp
->filename
));
580 return cx
->isExceptionPending();
582 uint32_t lineNumber
= reportp
->lineno
;
583 uint32_t columnNumber
= reportp
->column
;
585 RootedString
stack(cx
, ComputeStackString(cx
));
587 return cx
->isExceptionPending();
589 js::ScopedJSFreePtr
<JSErrorReport
> report(CopyErrorReport(cx
, reportp
));
591 return cx
->isExceptionPending();
593 RootedObject
errObject(cx
, ErrorObject::create(cx
, exnType
, stack
, fileName
,
594 lineNumber
, columnNumber
, &report
, messageStr
));
596 return cx
->isExceptionPending();
599 RootedValue
errValue(cx
, ObjectValue(*errObject
));
600 JS_SetPendingException(cx
, errValue
);
602 // Flag the error report passed in to indicate an exception was raised.
603 reportp
->flags
|= JSREPORT_EXCEPTION
;
608 IsDuckTypedErrorObject(JSContext
* cx
, HandleObject exnObject
, const char** filename_strp
)
611 if (!JS_HasProperty(cx
, exnObject
, js_message_str
, &found
) || !found
)
614 const char* filename_str
= *filename_strp
;
615 if (!JS_HasProperty(cx
, exnObject
, filename_str
, &found
) || !found
) {
616 /* Now try "fileName", in case this quacks like an Error */
617 filename_str
= js_fileName_str
;
618 if (!JS_HasProperty(cx
, exnObject
, filename_str
, &found
) || !found
)
622 if (!JS_HasProperty(cx
, exnObject
, js_lineNumber_str
, &found
) || !found
)
625 *filename_strp
= filename_str
;
629 JS_FRIEND_API(JSString
*)
630 js::ErrorReportToString(JSContext
* cx
, JSErrorReport
* reportp
)
632 JSExnType type
= static_cast<JSExnType
>(reportp
->exnType
);
633 RootedString
str(cx
, cx
->runtime()->emptyString
);
634 if (type
!= JSEXN_NONE
)
635 str
= ClassName(GetExceptionProtoKey(type
), cx
);
636 RootedString
toAppend(cx
, JS_NewUCStringCopyN(cx
, MOZ_UTF16(": "), 2));
637 if (!str
|| !toAppend
)
639 str
= ConcatStrings
<CanGC
>(cx
, str
, toAppend
);
642 toAppend
= JS_NewUCStringCopyZ(cx
, reportp
->ucmessage
);
644 str
= ConcatStrings
<CanGC
>(cx
, str
, toAppend
);
649 js_ReportUncaughtException(JSContext
* cx
)
651 if (!cx
->isExceptionPending())
655 if (!cx
->getPendingException(&exn
))
658 cx
->clearPendingException();
661 if (!err
.init(cx
, exn
)) {
662 cx
->clearPendingException();
666 cx
->setPendingException(exn
);
667 CallErrorReporter(cx
, err
.message(), err
.report());
668 cx
->clearPendingException();
672 ErrorReport::ErrorReport(JSContext
* cx
)
675 ownedMessage(nullptr),
682 ErrorReport::~ErrorReport()
687 js_free(ownedMessage
);
688 if (ownedReport
.messageArgs
) {
690 * js_ExpandErrorArguments owns its messageArgs only if it had to
691 * inflate the arguments (from regular |char*|s), which is always in
695 while (ownedReport
.messageArgs
[i
])
696 js_free(const_cast<char16_t
*>(ownedReport
.messageArgs
[i
++]));
697 js_free(ownedReport
.messageArgs
);
699 js_free(const_cast<char16_t
*>(ownedReport
.ucmessage
));
703 ErrorReport::init(JSContext
* cx
, HandleValue exn
)
705 MOZ_ASSERT(!cx
->isExceptionPending());
708 * Because ToString below could error and an exception object could become
709 * unrooted, we must root our exception object, if any.
711 if (exn
.isObject()) {
712 exnObject
= &exn
.toObject();
713 reportp
= js_ErrorFromException(cx
, exnObject
);
715 JSCompartment
* comp
= exnObject
->compartment();
716 JSAddonId
* addonId
= comp
->addonId
;
718 UniqueChars
addonIdChars(JS_EncodeString(cx
, addonId
));
720 const char* filename
= nullptr;
722 if (reportp
&& reportp
->filename
) {
723 filename
= strrchr(reportp
->filename
, '/');
728 filename
= "FILE_NOT_FOUND";
730 char histogramKey
[64];
731 JS_snprintf(histogramKey
, sizeof(histogramKey
),
735 (reportp
? reportp
->lineno
: 0) );
736 cx
->runtime()->addTelemetry(JS_TELEMETRY_ADDON_EXCEPTIONS
, 1, histogramKey
);
739 // Be careful not to invoke ToString if we've already successfully extracted
740 // an error report, since the exception might be wrapped in a security
741 // wrapper, and ToString-ing it might throw.
743 str
= ErrorReportToString(cx
, reportp
);
745 str
= ToString
<CanGC
>(cx
, exn
);
748 cx
->clearPendingException();
750 // If js_ErrorFromException didn't get us a JSErrorReport, then the object
751 // was not an ErrorObject, security-wrapped or otherwise. However, it might
752 // still quack like one. Give duck-typing a chance. We start by looking for
753 // "filename" (all lowercase), since that's where DOMExceptions store their
754 // filename. Then we check "fileName", which is where Errors store it. We
755 // have to do it in that order, because DOMExceptions have Error.prototype
756 // on their proto chain, and hence also have a "fileName" property, but its
758 const char* filename_str
= "filename";
759 if (!reportp
&& exnObject
&& IsDuckTypedErrorObject(cx
, exnObject
, &filename_str
))
761 // Temporary value for pulling properties off of duck-typed objects.
764 RootedString
name(cx
);
765 if (JS_GetProperty(cx
, exnObject
, js_name_str
, &val
) && val
.isString())
766 name
= val
.toString();
768 cx
->clearPendingException();
770 RootedString
msg(cx
);
771 if (JS_GetProperty(cx
, exnObject
, js_message_str
, &val
) && val
.isString())
772 msg
= val
.toString();
774 cx
->clearPendingException();
776 // If we have the right fields, override the ToString we performed on
777 // the exception object above with something built out of its quacks
778 // (i.e. as much of |NameQuack: MessageQuack| as we can make).
780 // It would be nice to use ErrorReportToString here, but we can't quite
781 // do it - mostly because we'd need to figure out what JSExnType |name|
782 // corresponds to, which may not be any JSExnType at all.
784 RootedString
colon(cx
, JS_NewStringCopyZ(cx
, ": "));
787 RootedString
nameColon(cx
, ConcatStrings
<CanGC
>(cx
, name
, colon
));
790 str
= ConcatStrings
<CanGC
>(cx
, nameColon
, msg
);
799 if (JS_GetProperty(cx
, exnObject
, filename_str
, &val
)) {
800 JSString
* tmp
= ToString
<CanGC
>(cx
, val
);
802 filename
.encodeLatin1(cx
, tmp
);
804 cx
->clearPendingException();
806 cx
->clearPendingException();
810 if (!JS_GetProperty(cx
, exnObject
, js_lineNumber_str
, &val
) ||
811 !ToUint32(cx
, val
, &lineno
))
813 cx
->clearPendingException();
818 if (!JS_GetProperty(cx
, exnObject
, js_columnNumber_str
, &val
) ||
819 !ToUint32(cx
, val
, &column
))
821 cx
->clearPendingException();
825 reportp
= &ownedReport
;
826 new (reportp
) JSErrorReport();
827 ownedReport
.filename
= filename
.ptr();
828 ownedReport
.lineno
= lineno
;
829 ownedReport
.exnType
= int16_t(JSEXN_NONE
);
830 ownedReport
.column
= column
;
832 // Note that using |str| for |ucmessage| here is kind of wrong,
833 // because |str| is supposed to be of the format
834 // |ErrorName: ErrorMessage|, and |ucmessage| is supposed to
835 // correspond to |ErrorMessage|. But this is what we've historically
836 // done for duck-typed error objects.
838 // If only this stuff could get specced one day...
839 if (str
->ensureFlat(cx
) && strChars
.initTwoByte(cx
, str
))
840 ownedReport
.ucmessage
= strChars
.twoByteChars();
845 message_
= bytesStorage
.encodeLatin1(cx
, str
);
847 message_
= "unknown (can't convert to string)";
850 // This is basically an inlined version of
852 // JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
853 // JSMSG_UNCAUGHT_EXCEPTION, message_);
855 // but without the reporting bits. Instead it just puts all
856 // the stuff we care about in our ownedReport and message_.
857 populateUncaughtExceptionReport(cx
, message_
);
859 /* Flag the error as an exception. */
860 reportp
->flags
|= JSREPORT_EXCEPTION
;
867 ErrorReport::populateUncaughtExceptionReport(JSContext
* cx
, ...)
871 populateUncaughtExceptionReportVA(cx
, ap
);
876 ErrorReport::populateUncaughtExceptionReportVA(JSContext
* cx
, va_list ap
)
878 new (&ownedReport
) JSErrorReport();
879 ownedReport
.flags
= JSREPORT_ERROR
;
880 ownedReport
.errorNumber
= JSMSG_UNCAUGHT_EXCEPTION
;
881 // XXXbz this assumes the stack we have right now is still
882 // related to our exception object. It would be better if we
883 // could accept a passed-in stack of some sort instead.
884 NonBuiltinFrameIter
iter(cx
);
886 ownedReport
.filename
= iter
.scriptFilename();
887 ownedReport
.lineno
= iter
.computeLine(&ownedReport
.column
);
888 ownedReport
.isMuted
= iter
.mutedErrors();
891 if (!js_ExpandErrorArguments(cx
, js_GetErrorMessage
, nullptr,
892 JSMSG_UNCAUGHT_EXCEPTION
, &ownedMessage
,
893 &ownedReport
, ArgumentsAreASCII
, ap
)) {
897 reportp
= &ownedReport
;
898 message_
= ownedMessage
;
899 ownsMessageAndReport
= true;
903 js_CopyErrorObject(JSContext
* cx
, Handle
<ErrorObject
*> err
)
905 js::ScopedJSFreePtr
<JSErrorReport
> copyReport
;
906 if (JSErrorReport
* errorReport
= err
->getErrorReport()) {
907 copyReport
= CopyErrorReport(cx
, errorReport
);
912 RootedString
message(cx
, err
->getMessage());
913 if (message
&& !cx
->compartment()->wrap(cx
, &message
))
915 RootedString
fileName(cx
, err
->fileName(cx
));
916 if (!cx
->compartment()->wrap(cx
, &fileName
))
918 RootedString
stack(cx
, err
->stack(cx
));
919 if (!cx
->compartment()->wrap(cx
, &stack
))
921 uint32_t lineNumber
= err
->lineNumber();
922 uint32_t columnNumber
= err
->columnNumber();
923 JSExnType errorType
= err
->type();
925 // Create the Error object.
926 return ErrorObject::create(cx
, errorType
, stack
, fileName
,
927 lineNumber
, columnNumber
, ©Report
, message
);
931 JS::CreateError(JSContext
* cx
, JSExnType type
, HandleString stack
, HandleString fileName
,
932 uint32_t lineNumber
, uint32_t columnNumber
, JSErrorReport
* report
,
933 HandleString message
, MutableHandleValue rval
)
935 assertSameCompartment(cx
, stack
, fileName
, message
);
936 js::ScopedJSFreePtr
<JSErrorReport
> rep
;
938 rep
= CopyErrorReport(cx
, report
);
941 js::ErrorObject::create(cx
, type
, stack
, fileName
,
942 lineNumber
, columnNumber
, &rep
, message
));
946 rval
.setObject(*obj
);