1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
6 
7 #ifndef vm_ErrorReporting_h
8 #define vm_ErrorReporting_h
9 
10 #include <stdarg.h>
11 #include <utility>
12 
13 #include "jsapi.h"        // for JSErrorNotes, JSErrorReport
14 #include "jsfriendapi.h"  // for ScriptEnvironmentPreparer
15 
16 #include "js/UniquePtr.h"  // for UniquePtr
17 #include "js/Utility.h"    // for UniqueTwoByteChars
18 
19 namespace js {
20 
21 /**
22  * Metadata for a compilation error (or warning) at a particular offset, or at
23  * no offset (i.e. with respect to a script overall).
24  */
25 struct ErrorMetadata {
26   // The file/URL where the error occurred.
27   const char* filename;
28 
29   // The line and column numbers where the error occurred.  If the error
30   // is with respect to the entire script and not with respect to a
31   // particular location, these will both be zero.
32   uint32_t lineNumber;
33   uint32_t columnNumber;
34 
35   // If the error occurs at a particular location, context surrounding the
36   // location of the error: the line that contained the error, or a small
37   // portion of it if the line is long.  (If the error occurs within a
38   // regular expression, this context is based upon its pattern characters.)
39   //
40   // This information is provided on a best-effort basis: code populating
41   // ErrorMetadata instances isn't obligated to supply this.
42   JS::UniqueTwoByteChars lineOfContext;
43 
44   // If |lineOfContext| is provided, we show only a portion (a "window") of
45   // the line around the erroneous token -- the first char in the token, plus
46   // |lineOfContextRadius| chars before it and |lineOfContextRadius - 1|
47   // chars after it.  This is because for a very long line, the full line is
48   // (a) not that helpful, and (b) wastes a lot of memory.  See bug 634444.
49   static constexpr size_t lineOfContextRadius = 60;
50 
51   // If |lineOfContext| is non-null, its length.
52   size_t lineLength;
53 
54   // If |lineOfContext| is non-null, the offset within it of the token that
55   // triggered the error.
56   size_t tokenOffset;
57 
58   // Whether the error is "muted" because it derives from a cross-origin
59   // load.  See the comment in TransitiveCompileOptions in jsapi.h for
60   // details.
61   bool isMuted;
62 };
63 
64 class CompileError : public JSErrorReport {
65  public:
66   void throwError(JSContext* cx);
67 };
68 
69 class MOZ_STACK_CLASS ReportExceptionClosure final
70     : public ScriptEnvironmentPreparer::Closure {
71   JS::HandleValue exn_;
72 
73  public:
ReportExceptionClosure(JS::HandleValue exn)74   explicit ReportExceptionClosure(JS::HandleValue exn) : exn_(exn) {}
75 
76   bool operator()(JSContext* cx) override;
77 };
78 
79 /** Send a JSErrorReport to the warningReporter callback. */
80 extern void CallWarningReporter(JSContext* cx, JSErrorReport* report);
81 
82 /**
83  * Report a compile error during script processing prior to execution of the
84  * script.
85  */
86 extern void ReportCompileErrorLatin1(JSContext* cx, ErrorMetadata&& metadata,
87                                      UniquePtr<JSErrorNotes> notes,
88                                      unsigned errorNumber, va_list* args);
89 
90 extern void ReportCompileErrorUTF8(JSContext* cx, ErrorMetadata&& metadata,
91                                    UniquePtr<JSErrorNotes> notes,
92                                    unsigned errorNumber, va_list* args);
93 
94 /**
95  * Report a compile warning during script processing prior to execution of the
96  * script.  Returns true if the warning was successfully reported, false if an
97  * error occurred.
98  */
99 [[nodiscard]] extern bool ReportCompileWarning(JSContext* cx,
100                                                ErrorMetadata&& metadata,
101                                                UniquePtr<JSErrorNotes> notes,
102                                                unsigned errorNumber,
103                                                va_list* args);
104 
105 class GlobalObject;
106 
107 /**
108  * Report the given error Value to the given global.  The JSContext is not
109  * assumed to be in any particular realm, but the global and error are
110  * expected to be same-compartment.
111  */
112 extern void ReportErrorToGlobal(JSContext* cx,
113                                 JS::Handle<js::GlobalObject*> global,
114                                 JS::HandleValue error);
115 
116 enum ErrorArgumentsType {
117   ArgumentsAreUnicode,
118   ArgumentsAreASCII,
119   ArgumentsAreLatin1,
120   ArgumentsAreUTF8
121 };
122 
123 enum class IsWarning { No, Yes };
124 
125 /**
126  * Report an exception, using printf-style APIs to generate the error
127  * message.
128  */
129 extern bool ReportErrorVA(JSContext* cx, IsWarning isWarning,
130                           const char* format, ErrorArgumentsType argumentsType,
131                           va_list ap) MOZ_FORMAT_PRINTF(3, 0);
132 
133 extern bool ReportErrorNumberVA(JSContext* cx, IsWarning isWarning,
134                                 JSErrorCallback callback, void* userRef,
135                                 const unsigned errorNumber,
136                                 ErrorArgumentsType argumentsType, va_list ap);
137 
138 extern bool ReportErrorNumberUCArray(JSContext* cx, IsWarning isWarning,
139                                      JSErrorCallback callback, void* userRef,
140                                      const unsigned errorNumber,
141                                      const char16_t** args);
142 
143 extern bool ReportErrorNumberUTF8Array(JSContext* cx, IsWarning isWarning,
144                                        JSErrorCallback callback, void* userRef,
145                                        const unsigned errorNumber,
146                                        const char** args);
147 
148 extern bool ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
149                                    void* userRef, const unsigned errorNumber,
150                                    const char16_t** messageArgs,
151                                    ErrorArgumentsType argumentsType,
152                                    JSErrorReport* reportp, va_list ap);
153 
154 extern bool ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
155                                    void* userRef, const unsigned errorNumber,
156                                    const char** messageArgs,
157                                    ErrorArgumentsType argumentsType,
158                                    JSErrorReport* reportp, va_list ap);
159 
160 /*
161  * For cases when we do not have an arguments array.
162  */
163 extern bool ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
164                                    void* userRef, const unsigned errorNumber,
165                                    ErrorArgumentsType argumentsType,
166                                    JSErrorReport* reportp, va_list ap);
167 
168 extern bool ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
169                                    void* userRef, const unsigned errorNumber,
170                                    const char16_t** messageArgs,
171                                    ErrorArgumentsType argumentsType,
172                                    JSErrorNotes::Note* notep, va_list ap);
173 
174 /*
175  * If there is a pending exception, print it to stderr and clear it. Otherwise
176  * do nothing.
177  *
178  * For reporting bugs or unexpected errors in testing functions.
179  */
180 extern void MaybePrintAndClearPendingException(JSContext* cx);
181 
182 }  // namespace js
183 
184 #endif /* vm_ErrorReporting_h */
185