Building the below code in VS Release mode results in different behavior when running the resulting binary in .NET 4.6 vs 4.7.
static void Main(string[] args)
{
var c = new ChangeAFlagLater();
while (!c.Flag) ;
}
class ChangeAFlagLater
{
public ChangeAFlagLater()
{
Task.Delay(1000).ContinueWith(_ => Flag = true);
}
public bool Flag;
}
When running with 4.6, the while loop exits after the other thread changes Flag, but with .NET 4.7 it gets stuck looping forever. It's clear in the 4.7 disassembly that Flag isn't being checked again after entering the loop:
00007FF90031049F movzx eax,byte ptr [rsi+8]
00007FF9003104A3 test eax,eax
00007FF9003104A5 je 00007FF9003104A3
Obviously, Flag should be marked volatile since it's being changed by another thread, and doing so prevents the infinite loop (je goes to 49F instead). Unfortunately, we found this in a production release running on a machine that had .NET 4.7 installed on it through Windows Updates, so it's a rather sneaky change in behavior. We hadn't noticed it yet on our dev machines because we mostly run in debug/without compiler optimizations.
Is this change in JIT considered a bug or is it a known issue or something?
Building the below code in VS Release mode results in different behavior when running the resulting binary in .NET 4.6 vs 4.7.
When running with 4.6, the while loop exits after the other thread changes Flag, but with .NET 4.7 it gets stuck looping forever. It's clear in the 4.7 disassembly that Flag isn't being checked again after entering the loop:
Obviously, Flag should be marked volatile since it's being changed by another thread, and doing so prevents the infinite loop (
jegoes to49Finstead). Unfortunately, we found this in a production release running on a machine that had .NET 4.7 installed on it through Windows Updates, so it's a rather sneaky change in behavior. We hadn't noticed it yet on our dev machines because we mostly run in debug/without compiler optimizations.Is this change in JIT considered a bug or is it a known issue or something?