[release/7.0] JIT: fix gc hole in peephole optimizations #78109
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Backport of #78074 to release/7.0
/cc @AndyAyersMS
Customer Impact
Possible GC heap corruption, caused by an unsafe peephole optimization that straddles a nogc/gc codegen boundary.
Issue was found by our own internal stress testing.
The problem here should occur somewhat rarely; the vulnerable window is just one instruction wide, in an optimization that doesn't happen very often, and it may only happen on arm64 (though the fix includes patching x64 too).
However, a number of methods in Roslyn or in BCL utilities Roslyn uses are impacted, so despite the small window here the code paths may be executed quite often.
Testing
Normal CI innerloop, plus selected jitstress/gcstress outerloop.
SPMI diffs show one impacted method in Roslyn, on arm64. Local runs of the libraries tests show another 29 impacted methods including a more Roslyn methods and methods for
ImmutableArray<T>
.One impacted method is
https://github.com/dotnet/roslyn/blob/80277a5a67e34e17f0cc903ad8fb89ea4c8ea0ae/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisScope.cs#L184-L208
The problem arises when setting up args for the comparer call, because
AdditionalFile
is a small struct with two GC references that needs to be copied, and the copy is done in a nogc region. Right after the copy the GC field is read, and the peephole may elide this read as the register being loaded already has the right value from the nogc region code, but that register is not GC tracked. If a gc happens right after the nogc region is exited, the reference in that register may move without the register being updated.Risk
Low.
This fix prevents peephole optimizations that might straddle a nogc/gc codegen boundary.
IMPORTANT: Is this backport for a servicing release? If so and this change touches code that ships in a NuGet package, please make certain that you have added any necessary package authoring and gotten it explicitly reviewed.