1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 
41 #include "qv4errorobject_p.h"
42 #include <QtCore/qnumeric.h>
43 #include <QtCore/qmath.h>
44 #include <QtCore/QDateTime>
45 #include <QtCore/QStringList>
46 #include <QtCore/QDebug>
47 
48 #include "qv4string_p.h"
49 #include <private/qv4mm_p.h>
50 #include <private/qv4codegen_p.h>
51 
52 #ifndef Q_OS_WIN
53 #  include <time.h>
54 #  ifndef Q_OS_VXWORKS
55 #    include <sys/time.h>
56 #  else
57 #    include "qplatformdefs.h"
58 #  endif
59 #else
60 #  include <windows.h>
61 #endif
62 
63 using namespace QV4;
64 
init()65 void Heap::ErrorObject::init()
66 {
67     Object::init();
68     stackTrace = nullptr;
69 
70     Scope scope(internalClass->engine);
71     Scoped<QV4::ErrorObject> e(scope, this);
72 
73     if (internalClass == scope.engine->internalClasses(EngineBase::Class_ErrorProto))
74         return;
75 
76     setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
77     setProperty(scope.engine, QV4::ErrorObject::Index_StackSetter, Value::undefinedValue());
78     setProperty(scope.engine, QV4::ErrorObject::Index_FileName, Value::undefinedValue());
79     setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Value::undefinedValue());
80 }
81 
init(const Value & message,ErrorType t)82 void Heap::ErrorObject::init(const Value &message, ErrorType t)
83 {
84     Object::init();
85     errorType = t;
86 
87     Scope scope(internalClass->engine);
88     Scoped<QV4::ErrorObject> e(scope, this);
89 
90     setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
91     setProperty(scope.engine, QV4::ErrorObject::Index_StackSetter, Value::undefinedValue());
92 
93     e->d()->stackTrace = new StackTrace(scope.engine->stackTrace());
94     if (!e->d()->stackTrace->isEmpty()) {
95         setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
96         setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Value::fromInt32(e->d()->stackTrace->at(0).line));
97     }
98 
99     if (!message.isUndefined())
100         setProperty(scope.engine, QV4::ErrorObject::Index_Message, message);
101 }
102 
init(const Value & message,const QString & fileName,int line,int column,ErrorObject::ErrorType t)103 void Heap::ErrorObject::init(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t)
104 {
105     Q_UNUSED(fileName); // ####
106     Object::init();
107     errorType = t;
108 
109     Scope scope(internalClass->engine);
110     Scoped<QV4::ErrorObject> e(scope, this);
111 
112     setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
113     setProperty(scope.engine, QV4::ErrorObject::Index_StackSetter, Value::undefinedValue());
114 
115     e->d()->stackTrace = new StackTrace(scope.engine->stackTrace());
116     StackFrame frame;
117     frame.source = fileName;
118     frame.line = line;
119     frame.column = column;
120     e->d()->stackTrace->prepend(frame);
121 
122     Q_ASSERT(!e->d()->stackTrace->isEmpty());
123     setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
124     setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Value::fromInt32(e->d()->stackTrace->at(0).line));
125 
126     if (!message.isUndefined())
127         setProperty(scope.engine, QV4::ErrorObject::Index_Message, message);
128 }
129 
className(Heap::ErrorObject::ErrorType t)130 const char *ErrorObject::className(Heap::ErrorObject::ErrorType t)
131 {
132     switch (t) {
133     case Heap::ErrorObject::Error:
134         return "Error";
135     case Heap::ErrorObject::EvalError:
136         return "EvalError";
137     case Heap::ErrorObject::RangeError:
138         return "RangeError";
139     case Heap::ErrorObject::ReferenceError:
140         return "ReferenceError";
141     case Heap::ErrorObject::SyntaxError:
142         return "SyntaxError";
143     case Heap::ErrorObject::TypeError:
144         return "TypeError";
145     case Heap::ErrorObject::URIError:
146         return "URIError";
147     }
148     Q_UNREACHABLE();
149 }
150 
method_get_stack(const FunctionObject * b,const Value * thisObject,const Value *,int)151 ReturnedValue ErrorObject::method_get_stack(const FunctionObject *b, const Value *thisObject, const Value *, int)
152 {
153     ExecutionEngine *v4 = b->engine();
154     const ErrorObject *This = thisObject->as<ErrorObject>();
155     if (!This)
156         return v4->throwTypeError();
157     if (!This->d()->stack) {
158         QString trace;
159         for (int i = 0; i < This->d()->stackTrace->count(); ++i) {
160             if (i > 0)
161                 trace += QLatin1Char('\n');
162             const StackFrame &frame = This->d()->stackTrace->at(i);
163             trace += frame.function + QLatin1Char('@') + frame.source;
164             if (frame.line >= 0)
165                 trace += QLatin1Char(':') + QString::number(frame.line);
166         }
167         This->d()->stack.set(v4, v4->newString(trace));
168     }
169     return This->d()->stack->asReturnedValue();
170 }
171 
172 DEFINE_OBJECT_VTABLE(ErrorObject);
173 
init(const Value & msg)174 void Heap::SyntaxErrorObject::init(const Value &msg)
175 {
176     Heap::ErrorObject::init(msg, SyntaxError);
177 }
178 
init(const Value & msg,const QString & fileName,int lineNumber,int columnNumber)179 void Heap::SyntaxErrorObject::init(const Value &msg, const QString &fileName, int lineNumber, int columnNumber)
180 {
181     Heap::ErrorObject::init(msg, fileName, lineNumber, columnNumber, SyntaxError);
182 }
183 
init(const Value & message)184 void Heap::EvalErrorObject::init(const Value &message)
185 {
186     Heap::ErrorObject::init(message, EvalError);
187 }
188 
init(const Value & message)189 void Heap::RangeErrorObject::init(const Value &message)
190 {
191     Heap::ErrorObject::init(message, RangeError);
192 }
193 
init(const Value & message)194 void Heap::ReferenceErrorObject::init(const Value &message)
195 {
196     Heap::ErrorObject::init(message, ReferenceError);
197 }
198 
init(const Value & msg,const QString & fileName,int lineNumber,int columnNumber)199 void Heap::ReferenceErrorObject::init(const Value &msg, const QString &fileName, int lineNumber, int columnNumber)
200 {
201     Heap::ErrorObject::init(msg, fileName, lineNumber, columnNumber, ReferenceError);
202 }
203 
init(const Value & message)204 void Heap::TypeErrorObject::init(const Value &message)
205 {
206     Heap::ErrorObject::init(message, TypeError);
207 }
208 
init(const Value & message)209 void Heap::URIErrorObject::init(const Value &message)
210 {
211     Heap::ErrorObject::init(message, URIError);
212 }
213 
214 DEFINE_OBJECT_VTABLE(ErrorCtor);
215 DEFINE_OBJECT_VTABLE(EvalErrorCtor);
216 DEFINE_OBJECT_VTABLE(RangeErrorCtor);
217 DEFINE_OBJECT_VTABLE(ReferenceErrorCtor);
218 DEFINE_OBJECT_VTABLE(SyntaxErrorCtor);
219 DEFINE_OBJECT_VTABLE(TypeErrorCtor);
220 DEFINE_OBJECT_VTABLE(URIErrorCtor);
221 
init(QV4::ExecutionContext * scope)222 void Heap::ErrorCtor::init(QV4::ExecutionContext *scope)
223 {
224     Heap::FunctionObject::init(scope, QStringLiteral("Error"));
225 }
226 
init(QV4::ExecutionContext * scope,const QString & name)227 void Heap::ErrorCtor::init(QV4::ExecutionContext *scope, const QString &name)
228 {
229     Heap::FunctionObject::init(scope, name);
230 }
231 
virtualCallAsConstructor(const FunctionObject * f,const Value * argv,int argc,const Value * newTarget)232 ReturnedValue ErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
233 {
234     Value v = argc ? *argv : Value::undefinedValue();
235     return ErrorObject::create<ErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
236 }
237 
virtualCall(const FunctionObject * f,const Value *,const Value * argv,int argc)238 ReturnedValue ErrorCtor::virtualCall(const FunctionObject *f, const Value *, const Value *argv, int argc)
239 {
240     return f->callAsConstructor(argv, argc);
241 }
242 
init(QV4::ExecutionContext * scope)243 void Heap::EvalErrorCtor::init(QV4::ExecutionContext *scope)
244 {
245     Heap::FunctionObject::init(scope, QStringLiteral("EvalError"));
246 }
247 
virtualCallAsConstructor(const FunctionObject * f,const Value * argv,int argc,const Value * newTarget)248 ReturnedValue EvalErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
249 {
250     Value v = argc ? *argv : Value::undefinedValue();
251     return ErrorObject::create<EvalErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
252 }
253 
init(QV4::ExecutionContext * scope)254 void Heap::RangeErrorCtor::init(QV4::ExecutionContext *scope)
255 {
256     Heap::FunctionObject::init(scope, QStringLiteral("RangeError"));
257 }
258 
virtualCallAsConstructor(const FunctionObject * f,const Value * argv,int argc,const Value * newTarget)259 ReturnedValue RangeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
260 {
261     Value v = argc ? *argv : Value::undefinedValue();
262     return ErrorObject::create<RangeErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
263 }
264 
init(QV4::ExecutionContext * scope)265 void Heap::ReferenceErrorCtor::init(QV4::ExecutionContext *scope)
266 {
267     Heap::FunctionObject::init(scope, QStringLiteral("ReferenceError"));
268 }
269 
virtualCallAsConstructor(const FunctionObject * f,const Value * argv,int argc,const Value * newTarget)270 ReturnedValue ReferenceErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
271 {
272     Value v = argc ? *argv : Value::undefinedValue();
273     return ErrorObject::create<ReferenceErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
274 }
275 
init(QV4::ExecutionContext * scope)276 void Heap::SyntaxErrorCtor::init(QV4::ExecutionContext *scope)
277 {
278     Heap::FunctionObject::init(scope, QStringLiteral("SyntaxError"));
279 }
280 
virtualCallAsConstructor(const FunctionObject * f,const Value * argv,int argc,const Value * newTarget)281 ReturnedValue SyntaxErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
282 {
283     Value v = argc ? *argv : Value::undefinedValue();
284     return ErrorObject::create<SyntaxErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
285 }
286 
init(QV4::ExecutionContext * scope)287 void Heap::TypeErrorCtor::init(QV4::ExecutionContext *scope)
288 {
289     Heap::FunctionObject::init(scope, QStringLiteral("TypeError"));
290 }
291 
virtualCallAsConstructor(const FunctionObject * f,const Value * argv,int argc,const Value * newTarget)292 ReturnedValue TypeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
293 {
294     Value v = argc ? *argv : Value::undefinedValue();
295     return ErrorObject::create<TypeErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
296 }
297 
init(QV4::ExecutionContext * scope)298 void Heap::URIErrorCtor::init(QV4::ExecutionContext *scope)
299 {
300     Heap::FunctionObject::init(scope, QStringLiteral("URIError"));
301 }
302 
virtualCallAsConstructor(const FunctionObject * f,const Value * argv,int argc,const Value * newTarget)303 ReturnedValue URIErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
304 {
305     Value v = argc ? *argv : Value::undefinedValue();
306     return ErrorObject::create<URIErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
307 }
308 
init(ExecutionEngine * engine,Object * ctor,Object * obj,Heap::ErrorObject::ErrorType t)309 void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t)
310 {
311     Scope scope(engine);
312     ScopedString s(scope);
313     ScopedObject o(scope);
314     ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj));
315     ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(1));
316     obj->setProperty(Index_Constructor, ctor->d());
317     obj->setProperty(Index_Message, engine->id_empty()->d());
318     obj->setProperty(Index_Name, engine->newString(QString::fromLatin1(ErrorObject::className(t))));
319     obj->defineDefaultProperty(engine->id_toString(), method_toString, 0);
320 }
321 
method_toString(const FunctionObject * b,const Value * thisObject,const Value *,int)322 ReturnedValue ErrorPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
323 {
324     ExecutionEngine *v4 = b->engine();
325     const Object *o = thisObject->as<Object>();
326     if (!o)
327         return v4->throwTypeError();
328 
329     Scope scope(v4);
330     ScopedValue name(scope, o->get(scope.engine->id_name()));
331     QString qname;
332     if (name->isUndefined())
333         qname = QStringLiteral("Error");
334     else
335         qname = name->toQString();
336 
337     ScopedString s(scope, scope.engine->newString(QStringLiteral("message")));
338     ScopedValue message(scope, o->get(s));
339     QString qmessage;
340     if (!message->isUndefined())
341         qmessage = message->toQString();
342 
343     QString str;
344     if (qname.isEmpty()) {
345         str = qmessage;
346     } else if (qmessage.isEmpty()) {
347         str = qname;
348     } else {
349         str = qname + QLatin1String(": ") + qmessage;
350     }
351 
352     return scope.engine->newString(str)->asReturnedValue();
353 }
354