Skip to content

Commit 759f7bd

Browse files
authored
Provided a clarifying message to the debug agent initialization error (#4524)
#4524
1 parent adce920 commit 759f7bd

File tree

5 files changed

+72
-0
lines changed

5 files changed

+72
-0
lines changed

integration-testing/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
33
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
44
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask
55
import org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode
6+
import java.io.*
67

78
buildscript {
89
/*
@@ -212,6 +213,7 @@ tasks {
212213
jvmArgs("-javaagent:$coroutinesDebugJar")
213214
testClassesDirs = sourceSet.output.classesDirs
214215
classpath = sourceSet.runtimeClasspath
216+
System.setProperty("coroutines.debug.agent.path", coroutinesDebugJar.absolutePath) // todo: fixme
215217
}
216218

217219
create<Test>("javaConsumersTest") {
@@ -231,6 +233,7 @@ tasks {
231233
":jpmsTest:check",
232234
"smokeTest:build",
233235
"java8Test:check",
236+
"safeDebugAgentTest:runWithExpectedFailure"
234237
)
235238
}
236239

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import java.io.*
2+
3+
plugins {
4+
id("java")
5+
application
6+
}
7+
8+
repositories {
9+
mavenCentral()
10+
}
11+
12+
application {
13+
mainClass.set("Main")
14+
}
15+
16+
// In this test coroutine debug agent is attached as a javaagent vm argument
17+
// to a pure Java project (safeDebugAgentTest) with no Kotlin stdlib dependency.
18+
// In this case the error should be thrown from AgetnPremain class:
19+
// "java.lang.IllegalStateException: kotlinx.coroutines debug agent failed to load."
20+
tasks.register<Test>("runWithExpectedFailure") {
21+
val agentJar = System.getProperty("coroutines.debug.agent.path")
22+
val errorOutputStream = ByteArrayOutputStream()
23+
val standardOutputStream = ByteArrayOutputStream()
24+
25+
project.javaexec {
26+
mainClass.set("Main")
27+
classpath = sourceSets.main.get().runtimeClasspath
28+
jvmArgs = listOf("-javaagent:$agentJar")
29+
errorOutput = errorOutputStream
30+
standardOutput = standardOutputStream
31+
isIgnoreExitValue = true
32+
}
33+
34+
val expectedAgentError =
35+
"kotlinx.coroutines debug agent failed to load.\n" +
36+
"Please ensure that the Kotlin standard library is present in the classpath.\n" +
37+
"Alternatively, you can disable kotlinx.coroutines debug agent by removing `-javaagent=/path/kotlinx-coroutines-core.jar` from your VM arguments.\n"
38+
val errorOutput = errorOutputStream.toString()
39+
val standardOutput = standardOutputStream.toString()
40+
if (!errorOutput.contains(expectedAgentError)) {
41+
throw GradleException("':safeDebugAgentTest:runWithExpectedFailure' completed with an unexpected output:\n" + standardOutput + "\n" + errorOutput)
42+
}
43+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public class Main {
2+
public static void main(String[] args) {
3+
System.out.printf("OK!");
4+
}
5+
}

integration-testing/settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pluginManagement {
88
}
99

1010
include("smokeTest")
11+
include("safeDebugAgentTest")
1112
include("java8Test")
1213
include(":jpmsTest")
1314

kotlinx-coroutines-core/jvm/src/debug/internal/AgentPremain.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package kotlinx.coroutines.debug.internal
33
import android.annotation.*
44
import org.codehaus.mojo.animal_sniffer.*
55
import sun.misc.*
6+
import java.lang.IllegalStateException
67
import java.lang.instrument.*
78
import java.lang.instrument.ClassFileTransformer
89
import java.security.*
@@ -16,6 +17,25 @@ import java.security.*
1617
@IgnoreJRERequirement // Never touched on Android
1718
internal object AgentPremain {
1819

20+
// This should be the first property to ensure the check happens first! Add new properties only below!
21+
private val dummy = checkIfStdlibIsAvailable()
22+
23+
/**
24+
* This check ensures that kotlin-stdlib classes are loaded by the time AgentPremain is initialized;
25+
* otherwise the debug session would fail with `java.lang.NoClassDefFoundError: kotlin/Result`.
26+
*/
27+
private fun checkIfStdlibIsAvailable() {
28+
try {
29+
Result.success(42)
30+
} catch (t: Throwable) {
31+
throw IllegalStateException("kotlinx.coroutines debug agent failed to load.\n" +
32+
"Please ensure that the Kotlin standard library is present in the classpath.\n" +
33+
"Alternatively, you can disable kotlinx.coroutines debug agent by removing `-javaagent=/path/kotlinx-coroutines-core.jar` from your VM arguments.\n" +
34+
t.cause
35+
)
36+
}
37+
}
38+
1939
private val enableCreationStackTraces = runCatching {
2040
System.getProperty("kotlinx.coroutines.debug.enable.creation.stack.trace")?.toBoolean()
2141
}.getOrNull() ?: DebugProbesImpl.enableCreationStackTraces

0 commit comments

Comments
 (0)