From 0b79ab4fed913698f8ae5b2b523a2ef457ebe97f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 11 Jul 2008 18:11:13 -0600 Subject: [PATCH] fix race condition in compile function 1. Thread A calls function F, which needs to be compiled. So it compiles it. 2. Thread B calls function F, sees that it's already been compiled and so runs it. 3. Thread B calls function G from function F, and G needs to be compiled, but it needs to acquire the class lock first, which A owns. 4. Thread A causes a GC, walks thread B's stack, but function F has not yet been added to the method tree, so it thinks the stack has no frames. 5. Thread A finally adds function F to the method tree. 6. Thread A causes another GC and walks thread B's stack again, and this time it finds function F in the method tree. 7. AAAARRRRRGGGHHH!!!!!! --- src/compile.cpp | 60 ++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 3feffa8b05..b300bf83b1 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -4255,7 +4255,7 @@ visitStack(MyThread* t, Heap::Visitor* v) } else { break; } - } + } } void @@ -5074,42 +5074,40 @@ compile(MyThread* t, object method) { MyProcessor* p = processor(t); - if (methodCompiled(t, method) == p->defaultThunk) { - PROTECT(t, method); + PROTECT(t, method); - ACQUIRE(t, t->m->classLock); + ACQUIRE(t, t->m->classLock); + if (methodCompiled(t, method) == p->defaultThunk) { + initClass(t, methodClass(t, method)); + if (UNLIKELY(t->exception)) return; + if (methodCompiled(t, method) == p->defaultThunk) { - initClass(t, methodClass(t, method)); - if (UNLIKELY(t->exception)) return; + object compiled; + if (methodFlags(t, method) & ACC_NATIVE) { + compiled = p->nativeThunk; + } else { + Context context(t, method); + compiled = compile(t, &context); + if (UNLIKELY(t->exception)) return; + } - if (methodCompiled(t, method) == p->defaultThunk) { - object compiled; - if (methodFlags(t, method) & ACC_NATIVE) { - compiled = p->nativeThunk; - } else { - Context context(t, method); - compiled = compile(t, &context); - if (UNLIKELY(t->exception)) return; + set(t, method, MethodCompiled, compiled); + + if (methodVirtual(t, method)) { + classVtable(t, methodClass(t, method), methodOffset(t, method)) + = &singletonValue(t, compiled, 0); + } + + if ((methodFlags(t, method) & ACC_NATIVE) == 0) { + if (DebugMethodTree) { + fprintf(stderr, "insert method at %p\n", + &singletonValue(t, methodCompiled(t, method), 0)); } - - set(t, method, MethodCompiled, compiled); - - if (methodVirtual(t, method)) { - classVtable(t, methodClass(t, method), methodOffset(t, method)) - = &singletonValue(t, compiled, 0); - } - - if ((methodFlags(t, method) & ACC_NATIVE) == 0) { - if (DebugMethodTree) { - fprintf(stderr, "insert method at %p\n", - &singletonValue(t, methodCompiled(t, method), 0)); - } - methodTree(t) = treeInsert - (t, methodTree(t), method, methodTreeSentinal(t), - compareMethodBounds); - } + methodTree(t) = treeInsert + (t, methodTree(t), method, methodTreeSentinal(t), + compareMethodBounds); } } }