Closed
Description
This issue was spotted as part of PR #77728
[MethodImplAttribute(MethodImplOptions.NoInlining)]
static void lenfail(uint[] a, uint i)
{
if (i < a.Length)
{
i = a[i];
}
Consume(i,i+2);
}
static void Main(string[] args)
{
var arr = new uint[] { 1, 42, 3000 };
lenfail(arr,0xffffffff);
}
With the following set:
export DOTNET_TieredCompilation=0
export DOTNET_JitStressModeNames=STRESS_IF_CONVERSION_COST
export DOTNET_JITMinOpts=0
Get error:
Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at CSharpTutorials.Program.lenfail(UInt32[], UInt32)
at CSharpTutorials.Program.Main(System.String[])
[1] 2099041 abort (core dumped) ./bin/release/net7.0/linux-arm64/conditional.dll
Why? The load from a[i]
should only happen if the if
condition holds. With If Conversion, the load is effectively hoisted outside if
and is always executed.
This is the Assignment block the If Conversion sees. There are no flags here to indicate moving the ASG
before the compare is unsafe. Even more worrying, the IND
is marked as GTF_IND_NONFAULTING
.
STMT00003 ( 0x008[E-] ... 0x00B )
N012 ( 10, 12) [000018] -A--G---R-- * ASG int $145
N011 ( 1, 1) [000017] D------N--- +--* LCL_VAR int V01 arg1 d:3 $VN.Void
N010 ( 10, 12) [000031] n---G--N--- \--* IND int <l:$183, c:$c2>
N009 ( 7, 10) [000029] ----------- \--* ARR_ADDR byref int[] $2c0
N008 ( 7, 10) [000028] -------N--- \--* ADD byref $201
N003 ( 3, 4) [000027] ----------- +--* ADD byref $200
N001 ( 1, 1) [000019] ----------- | +--* LCL_VAR ref V00 arg0 u:1 (last use) $80
N002 ( 1, 2) [000026] ----------- | \--* CNS_INT long 16 $1c0
N007 ( 4, 6) [000025] ----------- \--* LSH long $241
N005 ( 2, 3) [000023] ---------U- +--* CAST long <- uint $240
N004 ( 1, 1) [000020] ----------- | \--* LCL_VAR int V01 arg1 u:1 (last use) $c0
N006 ( 1, 2) [000024] -------N--- \--* CNS_INT long 2 $1c1
Not quite sure yet on what needs to be fixed earlier on