From ef54a6d7cb70a476180af7db991a54e6447739cc Mon Sep 17 00:00:00 2001 From: Pavel Kunyavskiy Date: Mon, 14 Nov 2022 10:35:11 +0100 Subject: [PATCH] [K/N] Fix calls checker use-after-free in main thread deinit Calls checker was trying to read thread state while unlocking mutex in unregister thread function. At this point thread is already unregistered and reference to current thread node is dangling. To avoid this, we nullify this reference in advance, as its anyway explicitly passed to unregister function, not read from global. --- kotlin-native/runtime/src/mm/cpp/Memory.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/kotlin-native/runtime/src/mm/cpp/Memory.cpp b/kotlin-native/runtime/src/mm/cpp/Memory.cpp index d43475b74a5..962e47c2fbf 100644 --- a/kotlin-native/runtime/src/mm/cpp/Memory.cpp +++ b/kotlin-native/runtime/src/mm/cpp/Memory.cpp @@ -113,15 +113,16 @@ extern "C" void DeinitMemory(MemoryState* state, bool destroyRuntime) { AssertThreadState(state, ThreadState::kNative); auto* node = mm::FromMemoryState(state); if (destroyRuntime) { - ThreadStateGuard guard(state, ThreadState::kRunnable); - node->Get()->gc().ScheduleAndWaitFullGCWithFinalizers(); - // TODO: Why not just destruct `GC` object and its thread data counterpart entirely? - mm::GlobalData::Instance().gc().StopFinalizerThreadIfRunning(); - } - mm::ThreadRegistry::Instance().Unregister(node); - if (destroyRuntime) { + { + ThreadStateGuard guard(state, ThreadState::kRunnable); + node->Get()->gc().ScheduleAndWaitFullGCWithFinalizers(); + // TODO: Why not just destruct `GC` object and its thread data counterpart entirely? + mm::GlobalData::Instance().gc().StopFinalizerThreadIfRunning(); + } + // we can clear reference in advance, as Unregister function can't use it anyway mm::ThreadRegistry::ClearCurrentThreadData(); } + mm::ThreadRegistry::Instance().Unregister(node); } extern "C" void RestoreMemory(MemoryState*) {