1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * Error-reporting types and structures.
9 * Despite these types and structures existing in js/public, significant parts
10 * of their heritage date back to distant SpiderMonkey past, and they are not
11 * all universally well-thought-out as ideal, intended-to-be-permanent API.
12 * We may eventually replace this with something more consistent with
13 * ECMAScript the language and less consistent with '90s-era JSAPI inventions,
14 * but it's doubtful this will happen any time soon.
17 #ifndef js_ErrorReport_h
18 #define js_ErrorReport_h
20 #include "mozilla/Assertions.h" // MOZ_ASSERT
22 #include <iterator> // std::input_iterator_tag, std::iterator
23 #include <stddef.h> // size_t
24 #include <stdint.h> // int16_t, uint16_t
25 #include <string.h> // strlen
27 #include "jstypes.h" // JS_PUBLIC_API
29 #include "js/AllocPolicy.h" // js::SystemAllocPolicy
30 #include "js/CharacterEncoding.h" // JS::ConstUTF8CharsZ
31 #include "js/Exception.h" // JS::ExceptionStack
32 #include "js/RootingAPI.h" // JS::HandleObject, JS::RootedObject
33 #include "js/UniquePtr.h" // js::UniquePtr
34 #include "js/Vector.h" // js::Vector
36 struct JS_PUBLIC_API JSContext
;
37 class JS_PUBLIC_API JSString
;
40 * Possible exception types. These types are part of a JSErrorFormatString
41 * structure. They define which error to throw in case of a runtime error.
43 * JSEXN_WARN is used for warnings, that are not strictly errors but are handled
44 * using the generalized error reporting mechanism. (One side effect of this
45 * type is to not prepend 'Error:' to warning messages.) This value can go away
46 * if we ever decide to use an entirely separate mechanism for warnings.
50 JSEXN_FIRST
= JSEXN_ERR
,
59 JSEXN_DEBUGGEEWOULDRUN
,
60 JSEXN_WASMCOMPILEERROR
,
62 JSEXN_WASMRUNTIMEERROR
,
64 JSEXN_WARN
= JSEXN_ERROR_LIMIT
,
69 struct JSErrorFormatString
{
70 /** The error message name in ASCII. */
73 /** The error format string in ASCII. */
76 /** The number of arguments to expand in the formatted error message. */
79 /** One of the JSExnType constants above. */
83 using JSErrorCallback
=
84 const JSErrorFormatString
* (*)(void* userRef
, const unsigned errorNumber
);
87 * Base class that implements parts shared by JSErrorReport and
92 // The (default) error message.
93 // If ownsMessage_ is true, the it is freed in destructor.
94 JS::ConstUTF8CharsZ message_
;
97 // Source file name, URL, etc., or null.
100 // Unique identifier for the script source.
103 // Source line number.
106 // Zero-based column index in line.
109 // the error number, e.g. see js/public/friend/ErrorNumbers.msg.
110 unsigned errorNumber
;
112 // Points to JSErrorFormatString::name.
113 // This string must never be freed.
114 const char* errorMessageName
;
117 bool ownsMessage_
: 1;
126 errorMessageName(nullptr),
127 ownsMessage_(false) {}
129 ~JSErrorBase() { freeMessage(); }
132 const JS::ConstUTF8CharsZ
message() const { return message_
; }
134 void initOwnedMessage(const char* messageArg
) {
135 initBorrowedMessage(messageArg
);
138 void initBorrowedMessage(const char* messageArg
) {
139 MOZ_ASSERT(!message_
);
140 message_
= JS::ConstUTF8CharsZ(messageArg
, strlen(messageArg
));
143 JSString
* newMessageString(JSContext
* cx
);
150 * Notes associated with JSErrorReport.
154 class Note final
: public JSErrorBase
{};
157 // Stores pointers to each note.
158 js::Vector
<js::UniquePtr
<Note
>, 1, js::SystemAllocPolicy
> notes_
;
164 // Add an note to the given position.
165 bool addNoteASCII(JSContext
* cx
, const char* filename
, unsigned sourceId
,
166 unsigned lineno
, unsigned column
,
167 JSErrorCallback errorCallback
, void* userRef
,
168 const unsigned errorNumber
, ...);
169 bool addNoteLatin1(JSContext
* cx
, const char* filename
, unsigned sourceId
,
170 unsigned lineno
, unsigned column
,
171 JSErrorCallback errorCallback
, void* userRef
,
172 const unsigned errorNumber
, ...);
173 bool addNoteUTF8(JSContext
* cx
, const char* filename
, unsigned sourceId
,
174 unsigned lineno
, unsigned column
,
175 JSErrorCallback errorCallback
, void* userRef
,
176 const unsigned errorNumber
, ...);
178 JS_PUBLIC_API
size_t length();
180 // Create a deep copy of notes.
181 js::UniquePtr
<JSErrorNotes
> copy(JSContext
* cx
);
183 class iterator final
{
185 js::UniquePtr
<Note
>* note_
;
188 using iterator_category
= std::input_iterator_tag
;
189 using value_type
= js::UniquePtr
<Note
>;
190 using difference_type
= ptrdiff_t;
191 using pointer
= value_type
*;
192 using reference
= value_type
&;
194 explicit iterator(js::UniquePtr
<Note
>* note
= nullptr) : note_(note
) {}
196 bool operator==(iterator other
) const { return note_
== other
.note_
; }
197 bool operator!=(iterator other
) const { return !(*this == other
); }
198 iterator
& operator++() {
202 reference
operator*() { return *note_
; }
205 JS_PUBLIC_API iterator
begin();
206 JS_PUBLIC_API iterator
end();
210 * Describes a single error or warning that occurs in the execution of script.
212 class JSErrorReport
: public JSErrorBase
{
214 // Offending source line without final '\n'.
215 // If ownsLinebuf_ is true, the buffer is freed in destructor.
216 const char16_t
* linebuf_
;
218 // Number of chars in linebuf_. Does not include trailing '\0'.
219 size_t linebufLength_
;
221 // The 0-based offset of error token in linebuf_.
225 // Associated notes, or nullptr if there's no note.
226 js::UniquePtr
<JSErrorNotes
> notes
;
228 // One of the JSExnType constants.
231 // See the comment in TransitiveCompileOptions.
234 // This error report is actually a warning.
238 bool ownsLinebuf_
: 1;
249 ownsLinebuf_(false) {}
251 ~JSErrorReport() { freeLinebuf(); }
254 const char16_t
* linebuf() const { return linebuf_
; }
255 size_t linebufLength() const { return linebufLength_
; }
256 size_t tokenOffset() const { return tokenOffset_
; }
257 void initOwnedLinebuf(const char16_t
* linebufArg
, size_t linebufLengthArg
,
258 size_t tokenOffsetArg
) {
259 initBorrowedLinebuf(linebufArg
, linebufLengthArg
, tokenOffsetArg
);
262 void initBorrowedLinebuf(const char16_t
* linebufArg
, size_t linebufLengthArg
,
263 size_t tokenOffsetArg
);
265 bool isWarning() const { return isWarning_
; }
273 struct MOZ_STACK_CLASS JS_PUBLIC_API ErrorReportBuilder
{
274 explicit ErrorReportBuilder(JSContext
* cx
);
275 ~ErrorReportBuilder();
277 enum SniffingBehavior
{ WithSideEffects
, NoSideEffects
};
280 * Generate a JSErrorReport from the provided thrown value.
282 * If the value is a (possibly wrapped) Error object, the JSErrorReport will
283 * be exactly initialized from the Error object's information, without
284 * observable side effects. (The Error object's JSErrorReport is reused, if
287 * Otherwise various attempts are made to derive JSErrorReport information
288 * from |exnStack| and from the current execution state. This process is
289 * *definitely* inconsistent with any standard, and particulars of the
290 * behavior implemented here generally shouldn't be relied upon.
292 * If the value of |sniffingBehavior| is |WithSideEffects|, some of these
293 * attempts *may* invoke user-configurable behavior when the exception is an
294 * object: converting it to a string, detecting and getting its properties,
295 * accessing its prototype chain, and others are possible. Users *must*
296 * tolerate |ErrorReportBuilder::init| potentially having arbitrary effects.
297 * Any exceptions thrown by these operations will be caught and silently
298 * ignored, and "default" values will be substituted into the JSErrorReport.
300 * But if the value of |sniffingBehavior| is |NoSideEffects|, these attempts
301 * *will not* invoke any observable side effects. The JSErrorReport will
302 * simply contain fewer, less precise details.
304 * Unlike some functions involved in error handling, this function adheres
305 * to the usual JSAPI return value error behavior.
307 bool init(JSContext
* cx
, const JS::ExceptionStack
& exnStack
,
308 SniffingBehavior sniffingBehavior
);
310 JSErrorReport
* report() const { return reportp
; }
312 const JS::ConstUTF8CharsZ
toStringResult() const { return toStringResult_
; }
315 // More or less an equivalent of JS_ReportErrorNumber/js::ReportErrorNumberVA
316 // but fills in an ErrorReport instead of reporting it. Uses varargs to
317 // make it simpler to call js::ExpandErrorArgumentsVA.
319 // Returns false if we fail to actually populate the ErrorReport
320 // for some reason (probably out of memory).
321 bool populateUncaughtExceptionReportUTF8(JSContext
* cx
,
322 JS::HandleObject stack
, ...);
323 bool populateUncaughtExceptionReportUTF8VA(JSContext
* cx
,
324 JS::HandleObject stack
,
327 // Reports exceptions from add-on scopes to telemetry.
328 void ReportAddonExceptionToTelemetry(JSContext
* cx
);
330 // We may have a provided JSErrorReport, so need a way to represent that.
331 JSErrorReport
* reportp
;
333 // Or we may need to synthesize a JSErrorReport one of our own.
334 JSErrorReport ownedReport
;
336 // Root our exception value to keep a possibly borrowed |reportp| alive.
337 JS::RootedObject exnObject
;
339 // And for our filename.
340 JS::UniqueChars filename
;
342 // We may have a result of error.toString().
343 // FIXME: We should not call error.toString(), since it could have side
344 // effect (see bug 633623).
345 JS::ConstUTF8CharsZ toStringResult_
;
346 JS::UniqueChars toStringResultBytesStorage
;
349 // Writes a full report to a file descriptor. Does nothing for JSErrorReports
350 // which are warnings, unless reportWarnings is set.
351 extern JS_PUBLIC_API
void PrintError(JSContext
* cx
, FILE* file
,
352 JSErrorReport
* report
,
353 bool reportWarnings
);
355 extern JS_PUBLIC_API
void PrintError(JSContext
* cx
, FILE* file
,
356 const JS::ErrorReportBuilder
& builder
,
357 bool reportWarnings
);
361 #endif /* js_ErrorReport_h */