From 4ea1b99c1a6efe144af381ea538f93718e9baf74 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Sun, 15 Oct 2023 23:34:16 +0000 Subject: [PATCH] 8317262: LockStack::contains(oop) fails "assert(t->is_Java_thread()) failed: incorrect cast to JavaThread" Co-authored-by: Patricio Chilano Mateo Reviewed-by: stuefe, pchilanomate, rkennke, mli --- .../share/runtime/lockStack.inline.hpp | 12 ++- .../runtime/lockStack/TestStackWalk.java | 93 +++++++++++++++++++ 2 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/lockStack/TestStackWalk.java diff --git a/src/hotspot/share/runtime/lockStack.inline.hpp b/src/hotspot/share/runtime/lockStack.inline.hpp index 186c7169fae..9dd04d8f7fe 100644 --- a/src/hotspot/share/runtime/lockStack.inline.hpp +++ b/src/hotspot/share/runtime/lockStack.inline.hpp @@ -47,10 +47,14 @@ inline bool LockStack::can_push() const { } inline bool LockStack::is_owning_thread() const { - JavaThread* thread = JavaThread::current(); - bool is_owning = &thread->lock_stack() == this; - assert(is_owning == (get_thread() == thread), "is_owning sanity"); - return is_owning; + Thread* current = Thread::current(); + if (current->is_Java_thread()) { + JavaThread* thread = JavaThread::cast(current); + bool is_owning = &thread->lock_stack() == this; + assert(is_owning == (get_thread() == thread), "is_owning sanity"); + return is_owning; + } + return false; } inline void LockStack::push(oop o) { diff --git a/test/hotspot/jtreg/runtime/lockStack/TestStackWalk.java b/test/hotspot/jtreg/runtime/lockStack/TestStackWalk.java new file mode 100644 index 00000000000..7e0b26ea881 --- /dev/null +++ b/test/hotspot/jtreg/runtime/lockStack/TestStackWalk.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8317262 + * @library /testlibrary /test/lib + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+HandshakeALot -XX:GuaranteedSafepointInterval=1 TestStackWalk + */ + +import jvmti.JVMTIUtils; +import jdk.test.lib.Asserts; +import jdk.test.whitebox.WhiteBox; +import java.util.concurrent.CountDownLatch; + +public class TestStackWalk { + static Thread worker1; + static Thread worker2; + static volatile boolean done; + static volatile int counter = 0; + static Object lock = new Object(); + + public static void main(String... args) throws Exception { + worker1 = new Thread(() -> syncedWorker()); + worker1.start(); + worker2 = new Thread(() -> syncedWorker()); + worker2.start(); + Thread worker3 = new Thread(() -> stackWalker()); + worker3.start(); + + worker1.join(); + worker2.join(); + worker3.join(); + } + + public static void syncedWorker() { + synchronized (lock) { + while (!done) { + counter++; + } + } + } + + public static void stackWalker() { + // Suspend workers so the one looping waiting for "done" + // doesn't execute the handshake below, increasing the + // chances the VMThread will do it. + suspendWorkers(); + + WhiteBox wb = WhiteBox.getWhiteBox(); + long end = System.currentTimeMillis() + 20000; + while (end > System.currentTimeMillis()) { + wb.handshakeWalkStack(worker1, false /* all_threads */); + wb.handshakeWalkStack(worker2, false /* all_threads */); + } + + resumeWorkers(); + done = true; + } + + static void suspendWorkers() { + JVMTIUtils.suspendThread(worker1); + JVMTIUtils.suspendThread(worker2); + } + + static void resumeWorkers() { + JVMTIUtils.resumeThread(worker1); + JVMTIUtils.resumeThread(worker2); + } +}