diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2020-02-17 15:30:54 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-02-27 15:08:29 +0100 |
commit | 2b5e0f90112fe85872894fb16e811203d4d3671f (patch) | |
tree | c7e883e6dd2dddf9711f7f412d81873fc7a35244 /src/qml/jsruntime | |
parent | 40f2dbd5557da2103e03a3fb7682bbfda3ffd122 (diff) |
V4: Fix mark stack overruns
Instead of applying a heuristic on when to call drain() in unrelated
code, we check the stack limit on each push(). If the soft limit is
reached we try to drain. As drain() itself can push again, we try to
limit the stack size by allowing at most 65 recursions of drain(). If
none of that helps, we crash with a meaningful error message.
This allows us to remove all the hacky drain() calls in other parts of
the code.
Change-Id: Ib979339470da0e85981de8131e7997755b757c71
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 15 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4persistent.cpp | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 7 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value_p.h | 25 |
4 files changed, 11 insertions, 37 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index f1b20ce53b..e9cc789607 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1266,20 +1266,15 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) void ExecutionEngine::markObjects(MarkStack *markStack) { - for (int i = 0; i < NClasses; ++i) - if (classes[i]) { - classes[i]->mark(markStack); - if (markStack->top >= markStack->limit) - markStack->drain(); - } - markStack->drain(); + for (int i = 0; i < NClasses; ++i) { + if (Heap::InternalClass *c = classes[i]) + c->mark(markStack); + } identifierTable->markObjects(markStack); - for (auto compilationUnit: compilationUnits) { + for (auto compilationUnit: compilationUnits) compilationUnit->markObjects(markStack); - markStack->drain(); - } } ReturnedValue ExecutionEngine::throwError(const Value &value) diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 79c372348f..f4901e3e4d 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -240,7 +240,6 @@ void PersistentValueStorage::mark(MarkStack *markStack) if (Managed *m = p->values[i].as<Managed>()) m->mark(markStack); } - markStack->drain(); p = p->header.next; } diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 9613d064c4..66b79aa0e8 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -638,10 +638,11 @@ void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack) if (!ddata) return; - if (ddata->jsEngineId == markStack->engine->m_engineId) + const QV4::ExecutionEngine *engine = markStack->engine(); + if (ddata->jsEngineId == engine->m_engineId) ddata->jsWrapper.markOnce(markStack); - else if (markStack->engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object) - markStack->engine->m_multiplyWrappedQObjects->mark(object, markStack); + else if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object) + engine->m_multiplyWrappedQObjects->mark(object, markStack); } void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value) diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index ae12033eb4..42e97b1d36 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -537,29 +537,8 @@ struct ValueArray { } void mark(MarkStack *markStack) { - Value *v = values; - const Value *end = v + alloc; - if (alloc > 32*1024) { - // drain from time to time to avoid overflows in the js stack - Value::HeapBasePtr *currentBase = markStack->top; - while (v < end) { - v->mark(markStack); - ++v; - if (markStack->top >= currentBase + 32*1024) { - Value::HeapBasePtr *oldBase = markStack->base; - markStack->base = currentBase; - markStack->drain(); - markStack->base = oldBase; - } - } - } else { - while (v < end) { - v->mark(markStack); - if (markStack->top >= markStack->limit) - markStack->drain(); - ++v; - } - } + for (Value *v = values, *end = values + alloc; v < end; ++v) + v->mark(markStack); } }; |