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