-
Notifications
You must be signed in to change notification settings - Fork 150
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
invokeSuspend edge case fix #2228
base: main
Are you sure you want to change the base?
Conversation
try { | ||
stacks = getReturnStacks(owner, mn); | ||
} catch (AnalyzerException e) { | ||
//Something went wrong calculating return stacks, leave the method unmodified. |
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 is a silent failure
…test implementation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2228 +/- ##
============================================
- Coverage 70.74% 70.60% -0.14%
+ Complexity 10006 9997 -9
============================================
Files 842 843 +1
Lines 40346 40452 +106
Branches 6115 6130 +15
============================================
+ Hits 28542 28563 +21
- Misses 9054 9111 +57
- Partials 2750 2778 +28 ☔ View full report in Codecov by Sentry. |
Resolves #2201
Description
This PR addresses a bug we found when attempting to weave
invokeSuspend
in Kotlin Coroutines.The weaver replaces RETURN instructions with GOTO instructions. This replacement can be unsafe if the operand stack prior to the RETURN instruction is not tidied up (ie, has more operands than needed to perform the return). This issue was previously unknown to us, because most compilers already clear their return stacks. However, the Kotlin compiler intentionally adds extra operands to Coroutines methods (for debugging purposes) and doesn't clean them up.
The purpose of this PR is to check the offending method (
invokeSuspend
) and tidy up its return stacks before the return instructions are replaced with gotos.Structure
Here is how a method will be processed with this fix:
getInliner
ofMethodCallInlinerAdapter
. At this point, the method's bytecode has not been modified.invokeSuspend
, it is visited with aClearReturnAdapter
.ReturnInsnProcessor.clearReturnStacks()
, which :Issues
One issue that I couldn't figure out how to address is how to handle failures of the frame analyzer (will leave a comment on the code). Unfortunately, the weaver can't log anything, and propagating an error upwards is also probably not feasible. That means it is currently a silent failure.
Another issue we should take seriously whenever bytecode is being modified is thread safety. I have left several comments in the code about this.
Testing
New tests can be found in
ReturnInsnProcessorTest
andWeaveCoroutineTest
. A test dependency on coroutines has been added to the weaver, because coroutines are the only known way to get the compiler to make the weird bytecode.Other
Some utility methods are added to
WeaveUtils
, which I developed during the debugging of this fix and think would be helpful to keep for the future.Feature Flag
I added a non-public system property to disable this feature:
-Dnewrelic.config.class_transformer.clear_return_stacks=false
Setting this property to false will allow the AIOOB error through as before.