-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
[Fuzzlyn] Assertion failed 'tgtIG' during 'Generate code' #96224
Comments
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch Issue DetailsLast Fuzzlyn run failed on OS X ARM64 with the following assert:
Reduced example: using System.Runtime.CompilerServices;
public interface I0
{
}
public interface I1
{
}
public class C0
{
public long F0;
public long F2;
public bool F3;
public ulong F4;
public bool F5;
public C0(bool f3, bool f5)
{
F3 = f3;
}
public int M61()
{
return 10;
}
}
public class C1 : I0
{
public C0 F0;
public C1(C0 f0)
{
}
public sbyte M3(C0 arg0)
{
return default(sbyte);
}
public bool M68()
{
return true;
}
}
public struct S0 : I1
{
public ushort F0;
public byte F1;
public S0(ushort f0, byte f1)
{
F0 = f0;
F1 = f1;
}
}
public struct S1
{
public long F0;
public ushort F1;
public bool F2;
public byte F3;
public int F4;
public bool F5;
public byte F6;
public bool F7;
public sbyte F8;
public uint F9;
public S1(long f0, ushort f1, bool f2, byte f3, int f4, bool f5, byte f6, bool f7, sbyte f8, uint f9): this()
{
F0 = f0;
F1 = f1;
F2 = f2;
F3 = f3;
F4 = f4;
F5 = f5;
F6 = f6;
F7 = f7;
F8 = f8;
F9 = f9;
}
public void M43()
{
return;
}
public void M59()
{
return;
}
}
public class Program
{
public static IRuntime s_rt;
public static I1[] s_1 = new I1[]{new S0(1, 209)};
public static I0 s_12;
public static S0[, ] s_17;
public static S1 s_18;
public static C1[][] s_19;
public static ulong s_21;
public static C0[] s_23;
public static byte[, ] s_30 = new byte[, ]{{239, 192, 1, 1, 2, 1}, {149, 155, 1, 188, 177, 1}, {10, 1, 109, 241, 1, 99}, {11, 222, 0, 15, 1, 0}};
public static C0 s_33 = new C0(false, false);
public static byte s_39;
public static int[] s_46;
public static C1 s_49;
public static byte[] s_50 = new byte[]{82};
public static I0[] s_52 = new I0[]{new C1(new C0(false, true))};
public static C1[, ][] s_55;
public static int s_56;
public static S0 s_58;
public static short s_79 = 0;
public static short s_81;
public static short[][][, ][][] s_82;
public static ushort s_86;
public static void Main()
{
CollectibleALC alc = new CollectibleALC();
System.Reflection.Assembly asm = alc.LoadFromAssemblyPath(System.Reflection.Assembly.GetExecutingAssembly().Location);
System.Reflection.MethodInfo mi = asm.GetType(typeof(Program).FullName).GetMethod(nameof(MainInner));
System.Type runtimeTy = asm.GetType(typeof(Runtime).FullName);
mi.Invoke(null, new object[]{System.Activator.CreateInstance(runtimeTy)});
}
public static void MainInner(IRuntime rt)
{
s_rt = rt;
M0();
}
public static void M0()
{
M49(-114);
}
public static int M1()
{
return default(int);
}
public static void M17(int arg1, sbyte arg2, sbyte arg4, sbyte[][] arg5, ref ulong arg6)
{
return;
}
public static void M38()
{
return;
}
public static void M49(sbyte arg0)
{
byte[] var0 = s_50;
for (int var1 = 0; var1 < 2; var1++)
{
I1[][][] var2 = new I1[][][]{new I1[][]{new I1[]{new S0(20692, 2)}, new I1[]{new S0(65534, 1)}, new I1[]{new S0(20900, 155)}, new I1[]{new S0(13884, 116)}}};
short var3 = (short)(((M51() + 1) & 0) / (short)(short)M51());
s_rt.WriteLine("c_815", var1);
}
s_rt.WriteLine("c_817", var0[0]);
return;
}
public static uint M51()
{
long var5;
ref C0 var0 = ref s_23[0];
var0 = ref var0;
return 4108078157U;
}
public static void M56(I0[] arg0, S1 arg2, S1 arg3, int[][] arg4, long arg6, C1 arg7, byte arg8)
{
}
public static void M63(ref uint arg1)
{
return;
}
public static uint M79()
{
return default(uint);
}
public static void M86(ref sbyte arg0, ref ushort arg1)
{
return;
}
public static void M89(ref C0 arg0)
{
return;
}
public static void M15(C0 argThis, C0 arg0, long[] arg1)
{
return;
}
public static void M40(C1 argThis)
{
return;
}
public static void M62(S0 argThis, S0 arg0, ref ushort arg1, C1 arg3, ulong[] arg4, ref C0 arg5, ulong[][][] arg6, I0 arg7)
{
s_rt.WriteLine("c_998", argThis.F0);
return;
}
public static void M39(C1 argThis, I1 arg1)
{
return;
}
public static void M36(S0 argThis, C0 arg0, uint arg1, bool arg2, long arg3)
{
return;
}
public static short M26(S0 argThis, ulong arg1, ref bool[] arg2)
{
return 20181;
}
}
public interface IRuntime
{
void WriteLine<T>(string site, T value);
}
public class Runtime : IRuntime
{
public void WriteLine<T>(string site, T value) => System.Console.WriteLine(value);
}
public class CollectibleALC : System.Runtime.Loader.AssemblyLoadContext
{
public CollectibleALC(): base(true)
{
}
} cc @dotnet/jit-contrib, does anyone have an ARM64 Mac they can repro this failure on?
|
This looks like a possible GC info issue: running with |
The GC issue reproduces intermittently. I have never been able to reproduce it reliably. The reduced example here looks unrelated to the GC issue (different seed). Not sure why it does not show anything interesting in the comment header (please include it, the seed can be quite important) |
From the logs, the original program that resulted in the reduced example above hit the following assert:
Based on the comment header the reduced example might or might not hit the same assert (again, not totally sure what happened there, I will add it to my todo list to investigate this from the Fuzzlyn side once I'm back) |
The // Generated by Fuzzlyn v1.6 on 2023-12-24 17:50:10
// Run on Arm64 MacOS
// Seed: 17421103114350285504
// Reduced from 177.9 KiB to 1.7 KiB in 00:01:10
// Hits JIT assert in Release:
// Assertion failed 'tgtIG' in 'Program:Main(Fuzzlyn.ExecutionServer.IRuntime)' during 'Generate code' (IL size 96; hash 0xade6b36b; FullOpts)
//
// File: /Users/runner/work/1/s/src/coreclr/jit/emit.cpp Line: 5174
//
using System.Runtime.CompilerServices;
public class Program
{
public static IRuntime s_rt;
public static byte[] s_4;
public static long s_25;
public static bool s_29;
public static ushort[] s_46;
public static long s_59;
public static void Main()
{
CollectibleALC alc = new CollectibleALC();
System.Reflection.Assembly asm = alc.LoadFromAssemblyPath(System.Reflection.Assembly.GetExecutingAssembly().Location);
System.Reflection.MethodInfo mi = asm.GetType(typeof(Program).FullName).GetMethod(nameof(MainInner));
System.Type runtimeTy = asm.GetType(typeof(Runtime).FullName);
mi.Invoke(null, new object[]{System.Activator.CreateInstance(runtimeTy)});
}
public static void MainInner(IRuntime rt)
{
long[] vr5 = new long[]{0};
for (int vr6 = 0; vr6 < 2; vr6++)
{
var vr7 = new int[]{1};
vr5[0] = (M50(vr7) & 0) / (int)M58();
s_rt.WriteLine("c_339", s_46[0]);
s_rt.WriteLine("c_340", 5566640345371016742UL);
}
}
public static int M50(int[] arg0)
{
if (s_29)
{
s_59 = s_25;
}
return arg0[0];
}
public static ulong M58()
{
s_4 = new byte[]{0};
return 5566640345371016742UL;
}
}
public interface IRuntime
{
void WriteLine<T>(string site, T value);
}
public class Runtime : IRuntime
{
public void WriteLine<T>(string site, T value) => System.Console.WriteLine(value);
}
public class CollectibleALC : System.Runtime.Loader.AssemblyLoadContext
{
public CollectibleALC(): base(true)
{
}
} |
Let's repurpose this issue to track the |
@jakobbotsch I'm not able to reproduce this assert locally. Is there anything special I need to do? Here's what I've done:
I've tried with and without I notice the assertion is:
but the test fragment doesn't have a |
Your steps should replicate exactly what Fuzzlyn is doing (with the checked Core_Root). So it should be able to repro it.
At the end of the reduction process Fuzzlyn will try to produce a standalone version of the program. Before that, the program that reproduces the issue has dependencies on some interfaces shared with Fuzzlyn (e.g. this The bug here is that Fuzzlyn does not check if the very first version of a standalone program reproduces the error. It is unusual for it not to, because it should replicate exactly what the non-standalone program is doing, except with the ALC setup being done in a different place. // Generated by Fuzzlyn v1.6 on 2024-01-18 13:26:13
// Run on Arm64 Linux
// Seed: 17421103114350285504
// Reduced from 177.9 KiB to 0.9 KiB in 00:05:33
// Hits JIT assert in Release:
// Assertion failed 'tgtIG' in 'Program:Main(Fuzzlyn.ExecutionServer.IRuntime)' during 'Generate code' (IL size 98; hash 0xade6b36b; FullOpts)
//
// File: /runtime/src/coreclr/jit/emit.cpp Line: 5174
//
using System.Runtime.CompilerServices;
public class Program
{
public static Fuzzlyn.ExecutionServer.IRuntime s_rt;
public static byte[] s_4;
public static long s_25;
public static bool s_29;
public static long s_59;
public static void Main(Fuzzlyn.ExecutionServer.IRuntime rt)
{
long[] vr5 = new long[]{0};
for (int vr6 = 0; vr6 < 2; vr6++)
{
var vr7 = new int[]{1};
vr5[0] = (M50(vr7) & 0) / (int)M58();
ulong vr8 = 5566640345371016742UL;
long vr9 = vr5[0];
s_rt.Checksum("c_340", vr8);
s_rt.Checksum("c_341", vr9);
}
}
public static int M50(int[] arg0)
{
if (s_29)
{
s_59 = s_25;
}
return arg0[0];
}
public static ulong M58()
{
s_4 = new byte[]{0};
return 5566640345371016742UL;
} which is the exact source of the program that Fuzzlyn hit the assert on, but of course won't compile standalone as the interface is in a separate assembly. But at least it won't be misleading anymore. I'm working on adding the SPMI support you suggested. I've attached an SPMI collection that reproduces the issue (collected on linux-arm64, commit 77d643d) |
One thing I noticed with the original repro is it compiled fine (I couldn't repro the assert), but it failed to run. Maybe that's standard behavior for a Fuzzlyn repro? It was because |
Yeah, it's expected. Since the interesting behavior here is an assertion, no code was actually running, so Fuzzlyn was able to remove all of the initialization as part of simplifying the program. |
I can repro the test failure with the linked repro-24575.zip MC file. The failure is because of the following:
One fix is to pay more attention to |
Throw helper blocks are created in morph, then possibly removed if unnecessary in StackLevelSetter (under optimization). However, there was a case where StackLevelSetter removed an OVERFLOW throw helper block after optimization proved it unnecessary because of a constant zero dividend, but between StackLevelSetter and codegen, LSRA introduced a RELOAD node above the constant zero that `GenTree::CanDivOrModPossiblyOverflow()` didn't understand, thus causing it to think that overflow was possible. Codegen looked for the OVERFLOW throw helper block and couldn't find it. There are multiple fixes here, somewhat "defense in depth": - If `StackLevelSetter::SetThrowHelperBlocks()` determines a node can't throw divide-by-zero or ArithmeticException (overflow), it marks the node GTF_DIV_MOD_NO_BY_ZERO / GTF_DIV_MOD_NO_OVERFLOW, respectively. This is what morph does earlier in compilation. - `genMarkLabelsForCodegen()` does not mark throw helper blocks where `acdUsed` is false, to avoid marking deleted blocks. - More asserts are added that `acdUsed` is true when codegen goes to generate a branch to a throw helper. - `GenTree::OperExceptions` / `CanDivOrModPossiblyOverflow` are changed to skip COPY/RELOAD nodes. Fixes dotnet#96224
Throw helper blocks are created in morph, then possibly removed if unnecessary in StackLevelSetter (under optimization). However, there was a case where StackLevelSetter removed an OVERFLOW throw helper block after optimization proved it unnecessary because of a constant zero dividend, but between StackLevelSetter and codegen, LSRA introduced a RELOAD node above the constant zero that `GenTree::CanDivOrModPossiblyOverflow()` didn't understand, thus causing it to think that overflow was possible. Codegen looked for the OVERFLOW throw helper block and couldn't find it. There are multiple fixes here, somewhat "defense in depth": - If `StackLevelSetter::SetThrowHelperBlocks()` determines a node can't throw divide-by-zero or ArithmeticException (overflow), it marks the node GTF_DIV_MOD_NO_BY_ZERO / GTF_DIV_MOD_NO_OVERFLOW, respectively. This is what morph does earlier in compilation. - `genMarkLabelsForCodegen()` does not mark throw helper blocks where `acdUsed` is false, to avoid marking deleted blocks. - More asserts are added that `acdUsed` is true when codegen goes to generate a branch to a throw helper. - `GenTree::OperExceptions` / `CanDivOrModPossiblyOverflow` are changed to skip COPY/RELOAD nodes. Fixes #96224
Throw helper blocks are created in morph, then possibly removed if unnecessary in StackLevelSetter (under optimization). However, there was a case where StackLevelSetter removed an OVERFLOW throw helper block after optimization proved it unnecessary because of a constant zero dividend, but between StackLevelSetter and codegen, LSRA introduced a RELOAD node above the constant zero that `GenTree::CanDivOrModPossiblyOverflow()` didn't understand, thus causing it to think that overflow was possible. Codegen looked for the OVERFLOW throw helper block and couldn't find it. There are multiple fixes here, somewhat "defense in depth": - If `StackLevelSetter::SetThrowHelperBlocks()` determines a node can't throw divide-by-zero or ArithmeticException (overflow), it marks the node GTF_DIV_MOD_NO_BY_ZERO / GTF_DIV_MOD_NO_OVERFLOW, respectively. This is what morph does earlier in compilation. - `genMarkLabelsForCodegen()` does not mark throw helper blocks where `acdUsed` is false, to avoid marking deleted blocks. - More asserts are added that `acdUsed` is true when codegen goes to generate a branch to a throw helper. - `GenTree::OperExceptions` / `CanDivOrModPossiblyOverflow` are changed to skip COPY/RELOAD nodes. Fixes dotnet#96224
Last Fuzzlyn run failed on OS X ARM64 with the following assert:
Reduced example:
cc @dotnet/jit-contrib, does anyone have an ARM64 Mac they can repro this failure on?
The text was updated successfully, but these errors were encountered: