1/*
2 * Copyright (C) 1999-2001 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003-2019 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Eric Seidel ([email protected])
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "config.h"
25#include "Error.h"
26
27#include "ConstructData.h"
28#include "ErrorConstructor.h"
29#include "ExceptionHelpers.h"
30#include "FunctionPrototype.h"
31#include "Interpreter.h"
32#include "JSArray.h"
33#include "JSCInlines.h"
34#include "JSFunction.h"
35#include "JSGlobalObject.h"
36#include "JSObject.h"
37#include "JSString.h"
38#include "NativeErrorConstructor.h"
39#include "SourceCode.h"
40#include "StackFrame.h"
41#include "SuperSampler.h"
42
43namespace JSC {
44
45JSObject* createError(JSGlobalObject* globalObject, const String& message, ErrorInstance::SourceAppender appender)
46{
47 ASSERT(!message.isEmpty());
48 return ErrorInstance::create(globalObject, globalObject->vm(), globalObject->errorStructure(), message, appender, TypeNothing, true);
49}
50
51JSObject* createEvalError(JSGlobalObject* globalObject, const String& message, ErrorInstance::SourceAppender appender)
52{
53 ASSERT(!message.isEmpty());
54 return ErrorInstance::create(globalObject, globalObject->vm(), globalObject->errorStructure(ErrorType::EvalError), message, appender, TypeNothing, true);
55}
56
57JSObject* createRangeError(JSGlobalObject* globalObject, const String& message, ErrorInstance::SourceAppender appender)
58{
59 ASSERT(!message.isEmpty());
60 return ErrorInstance::create(globalObject, globalObject->vm(), globalObject->errorStructure(ErrorType::RangeError), message, appender, TypeNothing, true);
61}
62
63JSObject* createReferenceError(JSGlobalObject* globalObject, const String& message, ErrorInstance::SourceAppender appender)
64{
65 ASSERT(!message.isEmpty());
66 return ErrorInstance::create(globalObject, globalObject->vm(), globalObject->errorStructure(ErrorType::ReferenceError), message, appender, TypeNothing, true);
67}
68
69JSObject* createSyntaxError(JSGlobalObject* globalObject, const String& message, ErrorInstance::SourceAppender appender)
70{
71 ASSERT(!message.isEmpty());
72 return ErrorInstance::create(globalObject, globalObject->vm(), globalObject->errorStructure(ErrorType::SyntaxError), message, appender, TypeNothing, true);
73}
74
75JSObject* createTypeError(JSGlobalObject* globalObject, const String& message, ErrorInstance::SourceAppender appender, RuntimeType type)
76{
77 ASSERT(!message.isEmpty());
78 return ErrorInstance::create(globalObject, globalObject->vm(), globalObject->errorStructure(ErrorType::TypeError), message, appender, type, true);
79}
80
81JSObject* createNotEnoughArgumentsError(JSGlobalObject* globalObject, ErrorInstance::SourceAppender appender)
82{
83 return createTypeError(globalObject, "Not enough arguments"_s, appender, TypeNothing);
84}
85
86JSObject* createURIError(JSGlobalObject* globalObject, const String& message, ErrorInstance::SourceAppender appender)
87{
88 ASSERT(!message.isEmpty());
89 return ErrorInstance::create(globalObject, globalObject->vm(), globalObject->errorStructure(ErrorType::URIError), message, appender, TypeNothing, true);
90}
91
92JSObject* createError(JSGlobalObject* globalObject, ErrorType errorType, const String& message)
93{
94 switch (errorType) {
95 case ErrorType::Error:
96 return createError(globalObject, message);
97 case ErrorType::EvalError:
98 return createEvalError(globalObject, message);
99 case ErrorType::RangeError:
100 return createRangeError(globalObject, message);
101 case ErrorType::ReferenceError:
102 return createReferenceError(globalObject, message);
103 case ErrorType::SyntaxError:
104 return createSyntaxError(globalObject, message);
105 case ErrorType::TypeError:
106 return createTypeError(globalObject, message);
107 case ErrorType::URIError:
108 return createURIError(globalObject, message);
109 }
110 ASSERT_NOT_REACHED();
111 return nullptr;
112}
113
114JSObject* createGetterTypeError(JSGlobalObject* globalObject, const String& message)
115{
116 ASSERT(!message.isEmpty());
117 auto* error = ErrorInstance::create(globalObject, globalObject->vm(), globalObject->errorStructure(ErrorType::TypeError), message);
118 error->setNativeGetterTypeError();
119 return error;
120}
121
122class FindFirstCallerFrameWithCodeblockFunctor {
123public:
124 FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame)
125 : m_startCallFrame(startCallFrame)
126 , m_foundCallFrame(nullptr)
127 , m_foundStartCallFrame(false)
128 , m_index(0)
129 { }
130
131 StackVisitor::Status operator()(StackVisitor& visitor) const
132 {
133 if (!m_foundStartCallFrame && (visitor->callFrame() == m_startCallFrame))
134 m_foundStartCallFrame = true;
135
136 if (m_foundStartCallFrame) {
137 if (!visitor->isWasmFrame() && visitor->callFrame()->codeBlock()) {
138 m_foundCallFrame = visitor->callFrame();
139 return StackVisitor::Done;
140 }
141 m_index++;
142 }
143
144 return StackVisitor::Continue;
145 }
146
147 CallFrame* foundCallFrame() const { return m_foundCallFrame; }
148 unsigned index() const { return m_index; }
149
150private:
151 CallFrame* m_startCallFrame;
152 mutable CallFrame* m_foundCallFrame;
153 mutable bool m_foundStartCallFrame;
154 mutable unsigned m_index;
155};
156
157std::unique_ptr<Vector<StackFrame>> getStackTrace(JSGlobalObject*, VM& vm, JSObject* obj, bool useCurrentFrame)
158{
159 JSGlobalObject* globalObject = obj->globalObject(vm);
160 if (!globalObject->stackTraceLimit())
161 return nullptr;
162
163 size_t framesToSkip = useCurrentFrame ? 0 : 1;
164 std::unique_ptr<Vector<StackFrame>> stackTrace = makeUnique<Vector<StackFrame>>();
165 vm.interpreter->getStackTrace(obj, *stackTrace, framesToSkip, globalObject->stackTraceLimit().value());
166 return stackTrace;
167}
168
169void getBytecodeIndex(VM& vm, CallFrame* startCallFrame, Vector<StackFrame>* stackTrace, CallFrame*& callFrame, BytecodeIndex& bytecodeIndex)
170{
171 FindFirstCallerFrameWithCodeblockFunctor functor(startCallFrame);
172 StackVisitor::visit(vm.topCallFrame, vm, functor);
173 callFrame = functor.foundCallFrame();
174 unsigned stackIndex = functor.index();
175 bytecodeIndex = BytecodeIndex(0);
176 if (stackTrace && stackIndex < stackTrace->size() && stackTrace->at(stackIndex).hasBytecodeIndex())
177 bytecodeIndex = stackTrace->at(stackIndex).bytecodeIndex();
178}
179
180bool getLineColumnAndSource(Vector<StackFrame>* stackTrace, unsigned& line, unsigned& column, String& sourceURL)
181{
182 line = 0;
183 column = 0;
184 sourceURL = String();
185
186 if (!stackTrace)
187 return false;
188
189 for (unsigned i = 0 ; i < stackTrace->size(); ++i) {
190 StackFrame& frame = stackTrace->at(i);
191 if (frame.hasLineAndColumnInfo()) {
192 frame.computeLineAndColumn(line, column);
193 sourceURL = frame.sourceURL();
194 return true;
195 }
196 }
197
198 return false;
199}
200
201bool addErrorInfo(VM& vm, Vector<StackFrame>* stackTrace, JSObject* obj)
202{
203 if (!stackTrace)
204 return false;
205
206 if (!stackTrace->isEmpty()) {
207 unsigned line;
208 unsigned column;
209 String sourceURL;
210 getLineColumnAndSource(stackTrace, line, column, sourceURL);
211 obj->putDirect(vm, vm.propertyNames->line, jsNumber(line));
212 obj->putDirect(vm, vm.propertyNames->column, jsNumber(column));
213 if (!sourceURL.isEmpty())
214 obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(vm, sourceURL));
215
216 obj->putDirect(vm, vm.propertyNames->stack, jsString(vm, Interpreter::stackTraceAsString(vm, *stackTrace)), static_cast<unsigned>(PropertyAttribute::DontEnum));
217
218 return true;
219 }
220
221 obj->putDirect(vm, vm.propertyNames->stack, vm.smallStrings.emptyString(), static_cast<unsigned>(PropertyAttribute::DontEnum));
222 return false;
223}
224
225void addErrorInfo(JSGlobalObject* globalObject, JSObject* obj, bool useCurrentFrame)
226{
227 VM& vm = globalObject->vm();
228 std::unique_ptr<Vector<StackFrame>> stackTrace = getStackTrace(globalObject, vm, obj, useCurrentFrame);
229 addErrorInfo(vm, stackTrace.get(), obj);
230}
231
232JSObject* addErrorInfo(VM& vm, JSObject* error, int line, const SourceCode& source)
233{
234 const String& sourceURL = source.provider()->url();
235
236 // The putDirect() calls below should really be put() so that they trigger materialization of
237 // the line/sourceURL properties. Otherwise, what we set here will just be overwritten later.
238 // But calling put() would be bad because we'd rather not do effectful things here. Luckily, we
239 // know that this will get called on some kind of error - so we can just directly ask the
240 // ErrorInstance to materialize whatever it needs to. There's a chance that we get passed some
241 // other kind of object, which also has materializable properties. But this code is heuristic-ey
242 // enough that if we're wrong in such corner cases, it's not the end of the world.
243 if (ErrorInstance* errorInstance = jsDynamicCast<ErrorInstance*>(vm, error))
244 errorInstance->materializeErrorInfoIfNeeded(vm);
245
246 // FIXME: This does not modify the column property, which confusingly continues to reflect
247 // the column at which the exception was thrown.
248 // https://bugs.webkit.org/show_bug.cgi?id=176673
249 if (line != -1)
250 error->putDirect(vm, vm.propertyNames->line, jsNumber(line));
251 if (!sourceURL.isNull())
252 error->putDirect(vm, vm.propertyNames->sourceURL, jsString(vm, sourceURL));
253 return error;
254}
255
256Exception* throwConstructorCannotBeCalledAsFunctionTypeError(JSGlobalObject* globalObject, ThrowScope& scope, const char* constructorName)
257{
258 return throwTypeError(globalObject, scope, makeString("calling ", constructorName, " constructor without new is invalid"));
259}
260
261Exception* throwTypeError(JSGlobalObject* globalObject, ThrowScope& scope)
262{
263 return throwException(globalObject, scope, createTypeError(globalObject));
264}
265
266Exception* throwTypeError(JSGlobalObject* globalObject, ThrowScope& scope, ASCIILiteral errorMessage)
267{
268 return throwTypeError(globalObject, scope, String(errorMessage));
269}
270
271Exception* throwTypeError(JSGlobalObject* globalObject, ThrowScope& scope, const String& message)
272{
273 return throwException(globalObject, scope, createTypeError(globalObject, message));
274}
275
276Exception* throwSyntaxError(JSGlobalObject* globalObject, ThrowScope& scope)
277{
278 return throwException(globalObject, scope, createSyntaxError(globalObject, "Syntax error"_s));
279}
280
281Exception* throwSyntaxError(JSGlobalObject* globalObject, ThrowScope& scope, const String& message)
282{
283 return throwException(globalObject, scope, createSyntaxError(globalObject, message));
284}
285
286Exception* throwGetterTypeError(JSGlobalObject* globalObject, ThrowScope& scope, const String& message)
287{
288 return throwException(globalObject, scope, createGetterTypeError(globalObject, message));
289}
290
291JSValue throwDOMAttributeGetterTypeError(JSGlobalObject* globalObject, ThrowScope& scope, const ClassInfo* classInfo, PropertyName propertyName)
292{
293 return throwGetterTypeError(globalObject, scope, makeString("The ", classInfo->className, '.', String(propertyName.uid()), " getter can only be used on instances of ", classInfo->className));
294}
295
296JSObject* createError(JSGlobalObject* globalObject, const String& message)
297{
298 return createError(globalObject, message, nullptr);
299}
300
301JSObject* createEvalError(JSGlobalObject* globalObject, const String& message)
302{
303 return createEvalError(globalObject, message, nullptr);
304}
305
306JSObject* createRangeError(JSGlobalObject* globalObject, const String& message)
307{
308 return createRangeError(globalObject, message, nullptr);
309}
310
311JSObject* createReferenceError(JSGlobalObject* globalObject, const String& message)
312{
313 return createReferenceError(globalObject, message, nullptr);
314}
315
316JSObject* createSyntaxError(JSGlobalObject* globalObject, const String& message)
317{
318 return createSyntaxError(globalObject, message, nullptr);
319}
320
321JSObject* createTypeError(JSGlobalObject* globalObject)
322{
323 return createTypeError(globalObject, "Type error"_s);
324}
325
326JSObject* createTypeError(JSGlobalObject* globalObject, const String& message)
327{
328 return createTypeError(globalObject, message, nullptr, TypeNothing);
329}
330
331JSObject* createNotEnoughArgumentsError(JSGlobalObject* globalObject)
332{
333 return createNotEnoughArgumentsError(globalObject, nullptr);
334}
335
336JSObject* createURIError(JSGlobalObject* globalObject, const String& message)
337{
338 return createURIError(globalObject, message, nullptr);
339}
340
341JSObject* createOutOfMemoryError(JSGlobalObject* globalObject)
342{
343 auto* error = createError(globalObject, "Out of memory"_s, nullptr);
344 jsCast<ErrorInstance*>(error)->setOutOfMemoryError();
345 return error;
346}
347
348JSObject* createOutOfMemoryError(JSGlobalObject* globalObject, const String& message)
349{
350
351 auto* error = createError(globalObject, makeString("Out of memory: ", message), nullptr);
352 jsCast<ErrorInstance*>(error)->setOutOfMemoryError();
353 return error;
354}
355
356} // namespace JSC
357