Fix crashes when GC triggers inside allocation inside initCallContext
authorSimon Hausmann <simon.hausmann@digia.com>
Fri, 28 Jun 2013 10:13:06 +0000 (12:13 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Fri, 28 Jun 2013 20:48:52 +0000 (22:48 +0200)
initCallContext allocates new managed memory required for the implementation of
the arguments objects. During that allocation a GC may happen itself, and it
may happen in turn that objects the context "owns" don't get marked.

This patch makes sure that newly allocated contexts are included in the chain
of contexts to mark by setting engine->current and context->parent early on,
before init*Context() can do any allocations.

Fixes tst_qjsvalue with MM_AGGRESSIVE_GC=1

Change-Id: Iebd444631691b6d00da8cfd20a1f760a5e73ac56
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/qml/v4/qv4context.cpp
src/qml/qml/v4/qv4context_p.h
src/qml/qml/v4/qv4engine.cpp

index f0178a7..ed01548 100644 (file)
@@ -127,14 +127,14 @@ unsigned int ExecutionContext::variableCount() const
 
 void GlobalContext::initGlobalContext(ExecutionEngine *eng)
 {
-    initBaseContext(Type_GlobalContext, eng);
+    initBaseContext(Type_GlobalContext, eng, /*parentContext*/0);
     thisObject = Value::fromObject(eng->globalObject);
     global = 0;
 }
 
 void WithContext::initWithContext(ExecutionContext *p, Object *with)
 {
-    initBaseContext(Type_WithContext, p->engine);
+    initBaseContext(Type_WithContext, p->engine, p);
     thisObject = p->thisObject;
     outer = p;
     lookups = p->lookups;
@@ -144,7 +144,7 @@ void WithContext::initWithContext(ExecutionContext *p, Object *with)
 
 void CatchContext::initCatchContext(ExecutionContext *p, String *exceptionVarName, const Value &exceptionValue)
 {
-    initBaseContext(Type_CatchContext, p->engine);
+    initBaseContext(Type_CatchContext, p->engine, p);
     strictMode = p->strictMode;
     thisObject = p->thisObject;
     outer = p;
@@ -154,9 +154,9 @@ void CatchContext::initCatchContext(ExecutionContext *p, String *exceptionVarNam
     this->exceptionValue = exceptionValue;
 }
 
-void CallContext::initCallContext(ExecutionEngine *engine, FunctionObject *function, Value *_arguments, int _argumentCount, const Value &_thisObject)
+void CallContext::initCallContext(ExecutionContext *parentContext, FunctionObject *function, Value *_arguments, int _argumentCount, const Value &_thisObject)
 {
-    initBaseContext(Type_CallContext, engine);
+    initBaseContext(Type_CallContext, parentContext->engine, parentContext);
 
     this->function = function;
     this->arguments = _arguments;
@@ -201,9 +201,9 @@ void CallContext::initCallContext(ExecutionEngine *engine, FunctionObject *funct
     }
 }
 
-void CallContext::initQmlContext(ExecutionEngine *engine, Object *qml, FunctionObject *function)
+void CallContext::initQmlContext(ExecutionContext *parentContext, Object *qml, FunctionObject *function)
 {
-    initBaseContext(Type_QmlContext, engine);
+    initBaseContext(Type_QmlContext, parentContext->engine, parentContext);
 
     this->function = function;
     this->arguments = 0;
@@ -604,3 +604,12 @@ void ExecutionContext::throwURIError(Value msg)
 {
     throwError(Value::fromObject(engine->newURIErrorObject(msg)));
 }
+
+
+void SimpleCallContext::initSimpleCallContext(ExecutionEngine *engine)
+{
+    initBaseContext(Type_SimpleCallContext, engine, engine->current);
+    function = 0;
+    arguments = 0;
+    argumentCount = 0;
+}
index cf4446d..dfe02bd 100644 (file)
@@ -105,14 +105,14 @@ struct Q_QML_EXPORT ExecutionContext
 
     const uchar **interpreterInstructionPointer;
 
-    void initBaseContext(Type type, ExecutionEngine *engine)
+    void initBaseContext(Type type, ExecutionEngine *engine, ExecutionContext *parentContext)
     {
         this->type = type;
         strictMode = false;
         marked = false;
         thisObject = Value::undefinedValue();
         this->engine = engine;
-        parent = 0;
+        parent = parentContext;
         outer = 0;
         lookups = 0;
         currentEvalCode = 0;
@@ -154,13 +154,7 @@ struct Q_QML_EXPORT ExecutionContext
 
 struct SimpleCallContext : public ExecutionContext
 {
-    void initSimpleCallContext(ExecutionEngine *engine)
-    {
-        initBaseContext(Type_SimpleCallContext, engine);
-        function = 0;
-        arguments = 0;
-        argumentCount = 0;
-    }
+    void initSimpleCallContext(ExecutionEngine *engine);
     FunctionObject *function;
     Value *arguments;
     unsigned int argumentCount;
@@ -168,9 +162,9 @@ struct SimpleCallContext : public ExecutionContext
 
 struct CallContext : public SimpleCallContext
 {
-    void initCallContext(QV4::ExecutionEngine *engine, FunctionObject *function, Value *args, int argc,
+    void initCallContext(ExecutionContext *parentContext, FunctionObject *function, Value *args, int argc,
                          const Value &thisObject);
-    void initQmlContext(QV4::ExecutionEngine *engine, Object *qml, QV4::FunctionObject *function);
+    void initQmlContext(ExecutionContext *parentContext, Object *qml, QV4::FunctionObject *function);
     bool needsOwnArguments() const;
 
     Value *locals;
index 721e323..b2893f0 100644 (file)
@@ -307,31 +307,28 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other)
 
 WithContext *ExecutionEngine::newWithContext(Object *with)
 {
-    ExecutionContext *p = current;
     WithContext *w = static_cast<WithContext *>(memoryManager->allocContext(sizeof(WithContext)));
-    w->initWithContext(p, with);
-    w->parent = current;
+    ExecutionContext *p = current;
     current = w;
+    w->initWithContext(p, with);
     return w;
 }
 
 CatchContext *ExecutionEngine::newCatchContext(String *exceptionVarName, const Value &exceptionValue)
 {
-    ExecutionContext *p = current;
     CatchContext *c = static_cast<CatchContext *>(memoryManager->allocContext(sizeof(CatchContext)));
-    c->initCatchContext(p, exceptionVarName, exceptionValue);
-    c->parent = current;
+    ExecutionContext *p = current;
     current = c;
+    c->initCatchContext(p, exceptionVarName, exceptionValue);
     return c;
 }
 
 CallContext *ExecutionEngine::newCallContext(FunctionObject *f, const Value &thisObject, Value *args, int argc)
 {
     CallContext *c = static_cast<CallContext *>(memoryManager->allocContext(requiredMemoryForExecutionContect(f, argc)));
-
-    c->initCallContext(this, f, args, argc, thisObject);
-    c->parent = current;
+    ExecutionContext *p = current;
     current = c;
+    c->initCallContext(p, f, args, argc, thisObject);
 
     return c;
 }
@@ -340,9 +337,9 @@ CallContext *ExecutionEngine::newQmlContext(FunctionObject *f, Object *qml)
 {
     CallContext *c = static_cast<CallContext *>(memoryManager->allocContext(requiredMemoryForExecutionContect(f, 0)));
 
-    c->initQmlContext(this, qml, f);
-    c->parent = current;
+    ExecutionContext *p = current;
     current = c;
+    c->initQmlContext(p, qml, f);
 
     return c;
 }
@@ -360,9 +357,9 @@ CallContext *ExecutionEngine::newCallContext(void *stackSpace, FunctionObject *f
 #endif
     }
 
-    c->initCallContext(this, f, args, argc, thisObject);
-    c->parent = current;
+    ExecutionContext *p = current;
     current = c;
+    c->initCallContext(p, f, args, argc, thisObject);
 
     return c;
 }
@@ -819,8 +816,10 @@ void ExecutionEngine::markObjects()
 
     for (int i = 0; i < argumentsAccessors.size(); ++i) {
         const Property &pd = argumentsAccessors.at(i);
-        pd.getter()->mark();
-        pd.setter()->mark();
+        if (FunctionObject *getter = pd.getter())
+            getter->mark();
+        if (FunctionObject *setter = pd.setter())
+            setter->mark();
     }
 
     ExecutionContext *c = current;