-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Attach coroutine debug agent safely #4524
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea of providing better error messages when the debug agent failed to attach is good. The proposed solution looks too complex to me, but maybe I'm missing some context.
// If this property is disabled, the debug agent will not be applied at all | ||
val applyDebugAgent = System.getProperty("kotlinx.coroutines.apply.debug.agent", "true").toBoolean() | ||
if (!applyDebugAgent) return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If someone controls the system environment at the point when premain
is being run, it means they can edit the command line which starts the process, and then, they can simply avoid specifying the Java agent. What's the purpose of adding a new property, then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, we don't need a property, we can just add the hint to remove the -javaagent
argument in the error message
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed this extra system property
* If `kotlinx.coroutines.apply.debug.agent` is set to `false`, the coroutine debug agent will not be applied. | ||
*/ | ||
@Suppress("unused") | ||
internal object SafeAgentPremain { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the purpose of this wrapper. What's stopping us from adding the check to AgentPremain
itself? Won't it be enough to call something like this function as the first thing in AgentPremain.premain
?
private fun checkIfStdlibIsAvailable() {
try {
Result.success(42)
} catch (_: Throwable) {
error("kotlinx.coroutines debug agent failed to load " +
"because the Kotlin standard library is not present in the classpath.")
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense, yes) This is the first point when we find out that stdlib is not loaded
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If someone later adds a field of some stdlib type to the AgentPremain class, it will cause problems at class loading time. The wrapper will protect against that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, actually this does not help, because the error happens when the AgentPremain
class is trying to initialize, at the moment AgentPremain.<clinit>
is called. And this check in premain
is already too late.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To protect against that, we could implement the check in AgentPremain
like so:
// This should be the first property, to ensure the check happens first! Add new properties only below!
val dummy = checkIfStdlibIsAvailable()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And replaced the wrapper class with this dummy property check
… if initialization of AgentPremain failed.
3a8fb3f
to
bed7062
Compare
please also add a test to ensure that the agent does no harm if stdlib is not available |
Recently there was a bug in the debugger IDEA-377586: the debug session failed at the start because initialization of the coroutine debug agent failed with this error:
This happened because debugger applied
kotlinx-coroutines-core
as a-javaagent
to the run configuration, which did not havekotlin-stdlib
in it's bootstrap classpath and the Kotlin classes would've only be loaded later.Ad a WA the debugger just skips run configurations like this and does not try to attach the coroutine debug agent at all.
This issue relates to the main problem of the coroutines agent attach (#4469), and SPI solution would help in this case too.
For now I suggest to provide some "safe" wrapper around
AgentPremain
, which would do nothing in caseAgentPremain
initialization fails.It would be bad to fail completely silently, as the user would want to know, what could be done to attach the agent anyway, e.g. add
kotlin-stdlib.jar
to the bootstrap classpath or smth. So maybe we can choose silent failure / clear error message by setting some system property.Anyway, I think it makes sense to provide some readable clear error message if something went wrong and give a hint how to attach the agent, because the debugger does not help in these cases.
If there may be a better solution, let's discuss please)