C# difference between Debug and Release - c#

Following code produces same output on 95% of machines, but on several there is difference. In Debug mode there is output:
Changing from New to Fin
OK
but in Release mode:
Changing from New to Fin
The OK line is missing. The project is targeted to .Net 4.0, build with VS 2015. You can download full sample here.
Source code
using System;
namespace Test
{
class Program
{
static void Main(string[] args)
{
Status current = Values.Status;
if (current != Next())
Console.WriteLine("OK");
}
static VO Values = new VO();
private static Status Next()
{
Status res = Status.Fin;
if (Values.Status == Status.New && Values.Cond)
res = Status.Fin;
else if (Values.Status == Status.Fin)
res = Status.Fin;
Log("Changing from {0} to {1}", Values.Status, res);
Values.Status = res;
return res;
}
public static void Log(string format, params object[] args)
{
Console.WriteLine(format, args);
}
}
public class VO
{
public Status Status;
public bool Cond;
}
public enum Status { New, Fin }
}
This is in my opinion the minimal version to reproduce the error. After removing some of the conditions in Next(), inlining Log method, replacing Values.Cond with false causes the application behaves correctly.
Edit: It's not hardware related - operating system was extracted to Hyper-V and the problem persists.

Based on Hans Passant's comment the problem was still reproducible with clrjit.dll version 4.6. After upgrading to 4.7 it disappears.

Related

Windows 10 Creators update .net 4.7 System.AccessViolationException issue

After updating Windows 10 to creators update with .net 4.7 I have a critical issue on starting very simple code.
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
class Program
{
private int? m_bool;
private bool prop {get{ return false;}}
void test()
{
//nothing
}
private object Test()
{
if (prop)
{
try
{
test();
}
catch (Exception) {}
m_bool = 1;
}
return null;
}
static void Main(string[] args)
{
new Program().Test();
}
}
Seems the similar issue is https://github.com/dotnet/coreclr/issues/10826
Anyone knows how to avoid that?
The issue is caused when an optimization is running on an unreachable basic block.
In your case the compiler inlines the get_prop method (which unconditionally returns false). This leads to JIT compiler to consider the region as unreachable. Typically the JIT compiler removes the unreachable code before we run the optimization, but adding a try/catch region causes the JIT not to delete these basic blocks.
If you want to prevent the issue you could disable optimizations, disable the inlining of get_prop or change the implementation of the get_prop method to be:
static bool s_alwaysFalse = false;
private bool prop {get{ return s_alwaysFalse;}}
We have had a couple of reports of this issue and we do have a fix ready and it will be provided to users in a upcoming update.

The 'Debug.Assert' statement does not work in Mono

I have this program here:
namespace TodoPlus {
using System.Diagnostics;
public class LameProg {
public LameProg() {}
public static void Main(string[] args) {
int a = 2;
int b = 3;
Debug.Assert(a == b, "Bleh");
System.Console.WriteLine("Haha, it didn't work");
}
}
}
And somehow, Debug.Assert is not working.
I am using Mono 2.10.5 and this is what I use to compile and execute:
dmcs LameProg.cs
mono ./LameProg.exe
How can I make this work? I wish it to have the same effect as the assert macro in C, which is to say it should just downright crash the program. Is it possible to do this with Debug.Assert or is there some other function that achieves this?
Debug.Assert is annotated with [ConditionalAttribute("DEBUG")]. This means that all invocations are removed by the compiler unless the DEBUG preprocessor symbol is defined. Try this:
$ dmcs -d:DEBUG LameProg.cs
Mono does not show a dialog box like Microsoft's .NET implementation when an assertion is hit. You need to set a TraceListener, e.g.
$ export MONO_TRACE_LISTENER=Console.Error
$ mono LameProg.exe
Debug.Assert invocations are typically used in debug builds and removed from release builds. If you want to make sure that a certain condition holds, and this check should be present in release builds, use an if statement and throw an exception:
public static void Main(string[] args)
{
int a = 2;
int b = 3;
if (a != b)
{
throw new Exception("Bleh");
}
System.Console.WriteLine("Haha it didn't work");
}
There's another trick: you can add "exit now" behavior through a TraceListener, because Debug.Assert failures trigger a call to Fail() in the trace listener.
You still need to -define:DEBUG (and TRACE?). I personally expect Assert() calls (in DEBUG builds) to stop my program, dump debug info and exit. So, this is how I do it:
In my code I install a custom trace listener to dump stack and add a call to Exit(). And viola! You have an industry standard response to Assert.Fail(). You could also, for example, print timestamps here, etc.
public class DumpStackTraceListener : TraceListener
{
public override void Write( string message )
{
Console.Write( message );
}
public override void WriteLine(string message)
{
Console.WriteLine( message );
}
public override void Fail(string message)
{
Fail( message, String.Empty );
}
public override void Fail(string message1, string message2)
{
if (null == message2)
message2 = String.Empty;
Console.WriteLine( "{0}: {1}", message1, message2 );
Console.WriteLine( "Stack Trace:" );
StackTrace trace = new StackTrace( true );
foreach (StackFrame frame in trace.GetFrames())
{
MethodBase frameClass = frame.GetMethod();
Console.WriteLine( " {2}.{3} {0}:{1}",
frame.GetFileName(),
frame.GetFileLineNumber(),
frameClass.DeclaringType,
frameClass.Name );
}
#if DEBUG
Console.WriteLine( "Exiting because Fail" );
Environment.Exit( 1 );
#endif
}
}
Combine with a call to:
#if DEBUG
Debug.Listeners.Add( new DumpStackTraceListener() );
#endif
And you're good to go.
I believe you need two things: the DEBUG attribute to the compiler, and a 'trace listener' for the runtime. I got it to work with
% export MONO_TRACE_LISTENER=Console.Error
% mcs -define:DEBUG -debug Prog.cs
% mono Prog.exe
That still doesn't exit immediately on assertion failure as I would have expected, but at least it prints something.

Bizarre ternary operator behavior in debugger on x64 platform

I'm using a very simple ternary expression in my C# code:
helperClass.SomeData = helperClass.HasData ? GetSomeData() : GetSomeOtherData();
In both cases, the functions on each path of the expression return a non-null object, but if I look at the result in the debugger, it is null until I reference it in the code such as using an assert:
Debug.Assert(helperClass.SomeData != null);
This only appears to happen if I use an "x64" or "Any CPU" platform setting in Debug mode. It's fine in "x86" mode.
I try to be very cautious before assuming I've found a bug in the compiler or debugger, but I can't find any other explanation for this behavior.
Here's a full class to do a repro, just call SomeClass.SomeAction() in the debugger in x64 mode and step through to see it:
public class SomeClass {
public bool HasData;
public object SomeData;
private SomeClass() {
HasData = false;
}
public static void SomeAction() {
var helperClass = new SomeClass();
// Exhibits weird debugger behavior of having helperClass.SomeData = null after this line:
helperClass.SomeData = helperClass.HasData ? GetSomeData() : GetSomeOtherData();
// Note that trying helperClass.SomeData.ToString() returns a debugger error saying SomeData is null
// But this code is just fine
//if(helperClass.HasData) {
// helperClass.SomeData = GetSomeData();
//}
//else {
// helperClass.SomeData = GetSomeOtherData();
//}
// In both cases though, after this line things are fine:
Debug.Assert(helperClass.SomeData != null);
}
private static object GetSomeData() {
return new object();
}
private static object GetSomeOtherData() {
return new object();
}
}
Am I missing something or is this a bug in the x64 debugger? I'm using debug mode so no optimizations should be present.
Taking Eric Lippert's advice that this is probably a bug, I've filed an official Connect bug for this issue: https://connect.microsoft.com/VisualStudio/feedback/details/684202
Thanks everyone for your feedback!
UPDATE: They got back to me and said they've fixed this corner case in the next version of the compiler. Hooray! :)
to me this doesn't seem a bug in the debugger but possibly of the compiler...
when changing the code to
{ helperClass.SomeData = helperClass.HasData ? GetSomeData() : GetSomeOtherData(); }
the IL generated is different and the debugger works as expected...

Some NGit stuff prevents C# application from shutting down correctly

I am trying to use NGit library in my application (C#, MS.NET 4.0). As we are on MS platform I have rebuilt the NGit for .NET Framework 4.0 under VS 2010. Most things are good and all the functionality works well but the application hangs on its shutdown. VS Debugger shows that some thread from Sharpen lib stays infinitely in the waiting state and nobody signals it to shutdown. That happens when I use any of the instance methods of NGit.Api.Git class (for static methods things seem to be OK). Did anybody experience such issues? Any suggestions?
Example of code using Git class:
Git myrepo = Git.Init().SetDirectory(#"C:\myrepo.git").SetBare(true).Call();
FetchResult fetchResult = myrepo.Fetch()
.SetProgressMonitor(new TextProgressMonitor())
.SetRemote(#"C:\projects\initialrepo")
.SetRefSpecs(new RefSpec("refs/heads/master:refs/heads/master"))
.Call();
//
// Some other work...
//
myrepo.GetRepository().Close();
And here is the place where the thread hangs:
Class Sharpen.ThreadExecutor, line 9 below (St.Monitor.Wait (pendingTasks)):
public void RunPoolThread ()
{
while (!IsTerminated ()) {
try {
Runnable r = null;
lock (pendingTasks) {
freeThreads++;
while (!IsTerminated () && pendingTasks.Count == 0)
ST.Monitor.Wait (pendingTasks);
if (IsTerminated ())
break;
r = pendingTasks.Dequeue ();
}
if (r != null)
r.Run ();
}
catch (ST.ThreadAbortException) {
ST.Thread.ResetAbort ();
}
catch {
}
}
}
I did get the library and ran the tests. I found some of the relevant tests to fail intermittently. I don't know if the test cases are wrong or whether there is an actual problem.
I reported the issue here: https://github.com/slluis/ngit/issues/8
I'll have a look at the particular code you added, I've just seen it
I tested the following code on
Linux (Mono 2.6.7, .NET 3.5)
Linux (Mono 2.11, .NET 4.0)
The problem appears to be that the static BatchingProgressMonitor (which is also constructed when you do not register the TextProgressMonitor) is never 'destructed', meaning that the alarmQueue with it's associated thread-pool is never Shutdown.
If you add the following public method to the class BatchingProgressMonitor:
public static void ShutdownNow()
{
alarmQueue.ShutdownNow();
}
you can have a 'workaround' by calling BatchingProgressMonitor.ShutdownNow() before exiting your application. This WorkedForMeTM. The sample code shows how to do that when you remove the #if/#endif.
.
using System;
using NGit;
using NGit.Api;
using NGit.Transport;
namespace Stacko
{
class MainClass
{
public static void Main (string[] args)
{
Git myrepo = Git.Init().SetDirectory(#"/tmp/myrepo.git").SetBare(true).Call();
{
var fetchResult = myrepo.Fetch()
.SetProgressMonitor(new TextProgressMonitor())
.SetRemote(#"/tmp/initial")
.SetRefSpecs(new RefSpec("refs/heads/master:refs/heads/master"))
.Call();
//
// Some other work...
//
myrepo.GetRepository().Close();
}
System.GC.Collect();
#if false
System.Console.WriteLine("Killing");
BatchingProgressMonitor.ShutdownNow();
#endif
System.Console.WriteLine("Done");
}
}
}
I'll report this at the issue tracker too. Edit Done: here
Cheers,
Seth

StackOverflowException in .NET 4

The following code works fine until I upgrade to .NET 4 (x64)
namespace CrashME
{
class Program
{
private static volatile bool testCrash = false;
private static void Crash()
{
try
{
}
finally
{
HttpRuntime.Cache.Insert("xxx", testCrash);
}
}
static void Main(string[] args)
{
Crash();
// Works on .NET 3.5 , crash on .NET 4
}
}
}
Did I just uncover a runtime bug, or is there some issue with my usage?
This would appear to be a bug in the CLR - you should report it to Microsoft.
Note that the StackOverflowException occurs as the CLR attempts to execute the Crash, not during the execution of the Crash method - the program in fact never enters the method. This would appear to indicate that this is some low-level failure in the CLR. (Also note that the thrown exception also has no stack trace).
This exception is incredibly specific to this situation - changing any one of a number of things fixes this, for example the following code works fine:
private static void Crash()
{
bool testCrash2 = testCrash;
try { }
finally
{
HttpRuntime.Cache.Insert("xxx", testCrash2);
}
}
I would recommend that you report this to Microsoft, but attempt to work around the issue by tweaking your code in the meantime.
I can reproduce it on an x86 machine. The following code also fails:
try
{
}
finally
{
var foo = new List<object>();
foo.Add(testCrash);
}
However, the following code succeeds:
try
{
}
finally
{
var foo = new List<bool>();
foo.Add(testCrash);
}
I thought it might have something to do with the boxing of volatile fields within the finally block, but then I tried the following (which also fails):
try
{
}
finally
{
bool[] foo = new bool[1];
foo[0] = testCrash;
}
Very interesting problem...

Categories

Resources