diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-11-08 08:20:04 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-11-11 17:33:12 +0100 |
commit | edc01fbfa430d6f0ce66f1871ab28e0f691ee252 (patch) | |
tree | c703a04ce0c8b067b440e938dfc76c99cf9867e8 /src | |
parent | ad31adffbd5c6d59c02454f17ff0a20bfd56e22c (diff) |
QML: Check for stack overflows when creating objects
Pick-to: 5.15 6.2 6.4
Fixes: QTBUG-106875
Change-Id: I3b0abda6948b79a9e3cf263f27885037fff1804c
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4jsonobject.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlincubator.cpp | 15 |
3 files changed, 24 insertions, 3 deletions
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index d1633abf52..067ddc7243 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -741,6 +741,9 @@ public: QV4::ExecutionContext *ctxt, int argc, const QV4::Value *argv); private: + template<int Frames> + friend struct ExecutionEngineCallDepthRecorder; + QV4::ReturnedValue fromData( QMetaType type, const void *ptr, Heap::Object *parent = nullptr, int property = -1, uint flags = 0); @@ -788,12 +791,15 @@ private: #define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \ ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4); +template<int Frames = 1> struct ExecutionEngineCallDepthRecorder { ExecutionEngine *ee; - ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ++ee->callDepth; } - ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; } + ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ee->callDepth += Frames; } + ~ExecutionEngineCallDepthRecorder() { ee->callDepth -= Frames; } + + bool hasOverflow() const { return ee->callDepth >= ExecutionEngine::s_maxCallDepth; } }; inline bool ExecutionEngine::checkStackLimits() diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 6fc854665c..4f46e605af 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -628,7 +628,7 @@ public: bool foundProblem() const { return m_callDepthRecorder.ee->hasException; } private: - ExecutionEngineCallDepthRecorder m_callDepthRecorder; + ExecutionEngineCallDepthRecorder<1> m_callDepthRecorder; }; static QString quote(const QString &str) diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 3c0a9dff36..6ee9e7e2ff 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -232,6 +232,7 @@ void QQmlIncubatorPrivate::forceCompletion(QQmlInstantiationInterrupt &i) } } + void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) { if (!compilationUnit) @@ -243,6 +244,20 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) // get a copy of the engine pointer as it might get reset; QQmlEnginePrivate *enginePriv = this->enginePriv; + // Incubating objects takes quite a bit more stack space than our usual V4 function + enum { EstimatedSizeInV4Frames = 2 }; + QV4::ExecutionEngineCallDepthRecorder<EstimatedSizeInV4Frames> callDepthRecorder( + compilationUnit->engine); + if (callDepthRecorder.hasOverflow()) { + QQmlError error; + error.setMessageType(QtCriticalMsg); + error.setUrl(compilationUnit->url()); + error.setDescription(QQmlComponent::tr("Maximum call stack size exceeded.")); + errors << error; + progress = QQmlIncubatorPrivate::Completed; + goto finishIncubate; + } + if (!vmeGuard.isOK()) { QQmlError error; error.setMessageType(QtInfoMsg); |