RFR: 8337331: crash: pinned virtual thread will lead to jvm crash when running with the javaagent option [v11]
Jaikiran Pai
jpai at openjdk.org
Wed Aug 7 12:16:33 UTC 2024
On Wed, 7 Aug 2024 08:31:35 GMT, Jaikiran Pai <jpai at openjdk.org> wrote:
>> I see that the `NoClassDefFoundError` failure that you are mentioning is actually being reported even in the GitHub Actions job failures. It does look odd (although might be a pre-known jtreg issue). It will need a bit of investigation to see what's going on.
>
> I was able to reproduce this `NoClassDefFoundError` in this new test locally. I will take a look to see if I can figure out what's going on.
I looked into this locally and this is a (known) bug in jtreg https://bugs.openjdk.org/browse/CODETOOLS-7902847.
What's happening here is that the tests are launched using make test TEST=test/hotspot/jtreg/:tier1_serviceability. One of those tests is the (pre-existing unrelated to this PR) AgentWithVThreadTest. That test has a `@compile AgentWithVThread.java AgentWithVThreadTest.java`. This triggers compilation of those classes and also any referenced classes in those 2 classes. One such class happens to be the test library's jdk.test.lib.Utils. This is a test library class (used/referenced indirectly in that test). jtreg ends up issuing a javac command with destination directory as the AgentWithVThreadTest's test specific work directory:
-d build/macosx-aarch64/test-support/jtreg_test_hotspot_jtreg_tier1_serviceability/classes/0/serviceability/jvmti/vthread/premain/AgentWithVThreadTest.d
So the `jdk.test.lib.Utils.class` (along with other classes) file ends up being compiled to `build/macosx-aarch64/test-support/jtreg_test_hotspot_jtreg_tier1_serviceability/classes/0/serviceability/jvmti/vthread/premain/AgentWithVThreadTest.d/jdk/test/lib/Utils.class`. During this compilation, the `jdk.test.lib.util.JavaAgentBuilder` doesn't get compiled because that class isn't referenced by AgentWithVThreadTest (neither directly or indirectly).
Then during the same test execution, jtreg notices a `@run` statement:
@run driver jdk.test.lib.util.JavaAgentBuilder ....
And to launch that run action, it first builds and compiles the jdk.test.lib.util.JavaAgentBuilder and since this is a test library class, jtreg ends up launching `javac` with a destination directory which is common/shared by multiple tests:
-d build/macosx-aarch64/test-support/jtreg_test_hotspot_jtreg_tier1_serviceability/classes/0/test/lib
Additionally, since this is being compiled in context of the AgentWithVThreadTest, jtreg also passes the test specific work directory (`build/macosx-aarch64/test-support/jtreg_test_hotspot_jtreg_tier1_serviceability/classes/0/serviceability/jvmti/vthread/premain/AgentWithVThreadTest.d`) as the classpath to the javac command. So effectively, this compilation ends up finding the `jdk.test.lib.Utils.class` in the test specific directory and doesn't recompile to the shared location. Since the `jdk.test.lib.util.JavaAgentBuilder` hasn't yet been compiled nor is located in the test specific work directory, javac ends up compiling it and placing it in the destination directory which was passed to the javac invocation and happens to be a shared directory for tests `build/macosx-aarch64/test-support/jtreg_test_hotspot_jtreg_tier1_serviceability/classes/0/test/lib`.
Effectively we now have a test library class (the `JavaAgentBuilder`) in the common shared directory and some of its referenced classes (`Utils.class`) in a test specific directory.
At a later point in time, this new test `TestPinCaseWithCFLH` being proposed in this PR, gets launched and jtreg notices the `@run` statement:
@run driver jdk.test.lib.util.JavaAgentBuilder ...
Just like previously, since this is a test library class, jtreg tries to locate this class in the shared directory and it finds it in the shared directory `build/macosx-aarch64/test-support/jtreg_test_hotspot_jtreg_tier1_serviceability/classes/0/test/lib` (since it was compiled to that location by an unrelated test). Since it finds the class, jtreg then skips compilation of that test library class and thus the `Utils.class` (or any of the classes referenced by `JavaAgentBuilder`) isn't recompiled again. jtreg then launches the test with this shared directory and this test's specific work directory (which is different from the AgentWithVThreadTest's work directory) in the classpath. Since neither of these directories contain the `Utils.class`, we end up with this missing class error.
Like I noted, this is a known problem in jtreg. I'll see if we can do something in that area.
For now though, I think one workaround is to add a:
@clean jdk.test.lib.util.JavaAgentBuilder
before the `@run` tag to allow for the jdk.test.lib.util.JavaAgentBuilder and its referenced classes to be compiled afresh (into the shared test library directory). This is what the change would look like in your PR:
diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java
index 02755a0289f..60564115f51 100644
--- a/test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java
+++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java
@@ -34,7 +34,7 @@
* @requires vm.jvmti
* @modules java.base/java.lang:+open
* @compile TestPinCaseWithCFLH.java
- * @build jdk.test.lib.Utils
+ * @clean jdk.test.lib.util.JavaAgentBuilder
* @run driver jdk.test.lib.util.JavaAgentBuilder
* TestPinCaseWithCFLH TestPinCaseWithCFLH.jar
* @run main/othervm/timeout=100 -Djdk.virtualThreadScheduler.maxPoolSize=1
I admit it's odd to be expecting the test to be doing this, but I think this should make the test stable. Can you give it a try?
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/20373#discussion_r1706894821
More information about the serviceability-dev
mailing list