Description
Under JitStress, optOptimizeBoolsGcStress
may transform x == null
into (x | x) == 0
or (x & x) == 0
for gc-typed x
. However the casting out of GC is done in a way that can lead to a hole in GC, as the xarch code generator will implement t = x | x; t == 0
as t = x; t |= x; t == 0
, and since t
is typed non-gc a GC interrupt between the first two instructions can relocate x
and so change the sense of the comparison.
This may explain many of the GC stress failures seen in the x86 gcstress=0xC jitstress=2 legs, for instance this one.
I have not yet confirmed this is the cause of the stress failures in those tests, but will update this bug if/when I do.
One such example (with zapdisable is) System.Threading.WaitHandle:WaitAll(ref,int,bool):bool
on x86, where there is a null check right at the start of the method, and the jit generates:
; prolog
push ebp
mov ebp,esp
push edi
push esi
push ebx
push eax
mov esi,ecx
mov edi,edx // GC info +ESI
; start of method body
mov ecx,esi
or ecx,esi // GC interrupt here can change ESI and not ECX
jne ...
This is split off from the ongoing efforts to triage and fix up gc stress in #9964 / dotnet/coreclr#17330.
cc @RussKeldorph @dotnet/jit-contrib
category:testing
theme:testing
skill-level:expert
cost:small