Difference between actual OOM and 2GB object OOM? - c#

I was wondering if there is some difference between the OOM exceptions thrown for an actual OOM (memory runs out), and the exception thrown when the 2GB object limit is hit?
I have the following code for causing the OOMs (no app.config changes, gcAllowVeryLargeObjects is by default set to false):
struct Data
{
double a;
double b;
}
// Causes OOM due to the 2GB object limit.
List<Data> a = new List<Data>(134217725);
// Causes OOM due to actual OOM.
List<Data[]> b = new List<Data[]>();
for (int i = 0; i < 13421772; i++)
{
b.Add(new Data[134217724]);
}
Now, I've executed the code from Visual Studio, and I get the following exceptions:
2GB object limit
System.OutOfMemoryException
HResult=0x8007000E
Message=Exception of type 'System.OutOfMemoryException' was thrown.
Source=mscorlib
StackTrace:
at System.Collections.Generic.List`1..ctor(Int32 capacity)
at ConsoleApp1.Program.Main(String[] args)
actual OOM
System.OutOfMemoryException
HResult=0x8007000E
Message=Exception of type 'System.OutOfMemoryException' was thrown.
Source=ConsoleApp1
StackTrace:
at ConsoleApp1.Program.Main(String[] args)
From here, it doesn't seem like there is a significant difference between the two exceptions (other than the stack trace/source).
On the other hand, I executed the exact same thing from LINQPad and got the following:
2GB limit
actual OOM
Executing RuntimeInformation.FrameworkDescription from both places results in .NET Framework 4.8.4341.0
My question is about detecting/differentiating between the two cases, although I am also curious as to why the error messages differ between the LINQPad and VS executions.

I can explain the difference between LinqPad and Visual Studio:
If you run x86 DEBUG and RELEASE .Net Framework 4.8 builds of the following code:
static void Main()
{
try
{
List<Data> a = new List<Data>(134217725);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
try
{
List<Data[]> b = new List<Data[]>();
for (int i = 0; i < 13421772; i++)
{
b.Add(new Data[134217724]);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
For the RELEASE build you get:
Array dimensions exceeded supported range.
Exception of type 'System.OutOfMemoryException' was thrown.
For the DEBUG build you get:
Exception of type 'System.OutOfMemoryException' was thrown.
Exception of type 'System.OutOfMemoryException' was thrown.
This implies that the LINQPAD version is RELEASE and the Visual Studio version is DEBUG.
So the answer is: Yes, there clearly is some difference, but:
Only the message differs
We should not rely on this never changing
It differs between DEBUG and RELEASE builds.
Aside:
On my PC, the DEBUG build of the test code above immediately throws the two OutOfMemoryException exceptions.
However, the RELEASE build quickly throws the first OutOfMemoryException, but it is several seconds before it throws the second exception. During this time, its memory usage increases (according to Task Manager).
So clearly there is some other difference under the hood, at least for .Net Framework 4.8. I haven't tried this with .Net 5 or .Net Core.

Related

.NET Core: Finally block not called on unhandled exception on Linux

I have created the following C# program:
namespace dispose_test
{
class Program
{
static void Main(string[] args)
{
using (var disp = new MyDisposable())
{
throw new Exception("Boom");
}
}
}
public class MyDisposable : IDisposable
{
public void Dispose()
{
Console.WriteLine("Disposed");
}
}
}
When I run this using dotnet run, I see the following behavior:
Windows: Exception text written to console, "Disposed" printed ~20 second later, program exits.
Linux: Exception text written to console, program exits immediately. "Disposed" never written.
The delay on Windows is annoying, but the fact that Dispose() isn't called at all on Linux is troubling. Is this expected behavior?
EDITS Clarifications/additions from the conversation below:
This is not specific to using/Dispose(), which is just a special case of try/finally. The behavior also occurs generally with try/finally - the finally block is not run. I have updated the title to reflect this.
I have also checked for the execution of Dispose() by writing a file to the filesystem, just to ensure that problem wasn't related to stdout being disconnected from the console before Dispose() is run in the case of an unhandled exception. Behavior was the same.
Dispose() does get called if the exception is caught anywhere within the application. It's when it goes completely unhandled by the application that this behavior occurs.
On Windows, the long gap is not due to compilation delay. I started timing when the exception text was written to the console.
My original experiment was doing dotnet run on both platforms, which means separate compilations, but I have also tried by doing dotnet publish on Windows and directly running the output on both platforms, with the same result. The only difference is that, when run directly on Linux, the text "Aborted (core dumped)" is written after the exception text.
Version details:
dotnet --version -> 1.0.4.
Compiling to netcoreapp1.1, running on .NET Core 1.1.
lsb-release -d -> Ubuntu 16.04.1 LTS
Official response is that this is an expected behavior.
Interestingly enough, the C# doc page on try-finally explicitly calls this out right at the top (emphasis mine)
Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up. For more information, see Unhandled Exception Processing in the CLR.
Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important. However, if you have statements in a finally block that must be run even in that situation, one solution is to add a catch block to the try-finally statement. Alternatively, you can catch the exception that might be thrown in the try block of a try-finally statement higher up the call stack. That is, you can catch the exception in the method that calls the method that contains the try-finally statement, or in the method that calls that method, or in any method in the call stack. If the exception is not caught, execution of the finally block depends on whether the operating system chooses to trigger an exception unwind operation.
One thing I found in my experimentation is that it doesn't appear to be enough to catch the exception, you have to handle it as well. If execution leaves the catch block via a throw, the finally will not run.
If you surround this with a try-catch, the finally block will run when the exception is caught (handled) by the outer catch.
static void Main(string[] args)
{
try
{
using (var disp = new MyDisposable())
{
throw new Exception("Boom");
}
}
catch (Exception e)
{
throw;
}
}

Catch All Unhandled Exceptions

I'm going to catch all unhandled exceptions in my Winforms app. Here is the shortened code:
[STAThread]
static void Main()
{
if (!AppDomain.CurrentDomain.FriendlyName.EndsWith("vshost.exe"))
{
Application.ThreadException += new ThreadExceptionEventHandler(MyCommonExceptionHandlingMethod);
}
Application.Run(new frmLogin());
}
private static void MyCommonExceptionHandlingMethod(object sender, ThreadExceptionEventArgs t)
{
Exception ex = t.Exception;
StackTrace trace = new StackTrace(ex, true);
var db = new MyDataContext();
Error error = new Error();
error.FormName = trace.GetFrame(0).GetMethod().ReflectedType.FullName;
error.LineNumber = trace.GetFrame(0).GetFileLineNumber();
error.ColumnNumber = trace.GetFrame(0).GetFileColumnNumber();
error.Message = ex.Message;
db.Errors.InsertOnSubmit(error);
db.SubmitChanges();
if (new frmError(ex).ShowDialog() != DialogResult.Yes)
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
The issue is that sometimes FormName, LineNumber and ColumnNumber are not correctly returned. Here is the result that I sometimes get:
--FormName-- --Line/Column-- --Message--
System.Linq.Enumerable 0 0 Sequence contains no matching element
System.RuntimeMethodHandle 0 0 Exception has been thrown by the target of an invocation.
System.Number 0 0 Input string was not in a correct format.
System.Number 0 0 Input string was not in a correct format.
System.ThrowHelper 0 0 Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
As you can see, LineNumbers and ColumnNumbers are 0. FormName is System.Linq.Enumerable ...
How can I solve the problem?
How can I solve the problem?
When no .pdb is present for a given module, the stack trace information will necessarily not be able to include file names, line, or column numbers.
To get them, you need to make sure you have the .NET .pdb available and loaded. There are a number of resources available which describe how to do this. See Cannot step into .NET framework source code, for example, or Advanced .NET Debugging - PDBs and Symbol Stores. You can use your favorite web search engine to find additional resources.
I'll note also that you are describing the type name as the "FormName", which is incorrect. It's only the form name when the exception was in fact thrown by your form. Unhandled exceptions are always bugs, and as such are very often thrown by framework or other library code, and the types won't be forms.
I will also mention that catching all exceptions is useful only for diagnosing bugs. This should not be used as an attempt to improve general reliability of a program (except to the extent that better diagnosis can allow you to fix bugs). When an unhandled exception occurs, you should log it and then kill the process. Allowing a process to continue executing after an unhandled exception occurs is dangerous for your data, and can lead to complacency with respect to bug-fixing.

Cannot unwind or Continue and Edit if Assert throw

I am trying to do Edit/Continue in VS2015 Debugger.
This works 100% in VS2013.
But, once I hit an Assert. I keep getting cannot Unwind errors.
I have tried adding AssertFailedException to CLR Exceptions in Exception Settings. And I tried toggling Debugging settings: Enable Just My Code. And Unwind the call stack on unhandled exceptions.
[TestMethod]
public void TEST()
{
int a = 5;
int b = 1;
Assert.AreEqual(a, b);
throw new AssertFailedException("THIS IS OK");
int c= a + b;
}
UPDATE:
Same fail when I tried several versions of the Microsoft.VisualStudio.QualitTools.UnitTestFramework library. 10.0.0 & 10.1.0 (file versions 12 and 14). I'm now trying the VS2015 Update2RC.
I tried it is working on VS2019.
In VS2019, Go to Debug > Windows > Exception Settings will show up "Break When Thrown" window.
Expand Common Language Runtime Exceptions
Check <All Common Language RunTime Exceptions not in this list>
Then you can unwind when Assert occured exceptions.

Unhandled Exception in C# Console Application causing AppCrash

I have a Windows Console application built in Visual Studio 2010 and it keeps crashing but the error is not caught by the visual studio debugging tool nor by try/catch statements in my code.
I have managed to locate the WER file on my system and would like to be able to understand the contents of the file so I can pinpoint exactally what is causing the unhandled exception.
I would be greatful if anyone can offer some idea on how I can use the following information to locate the process causing me this problem and also what the exception may be...
The information from the WER file is:
Version=1
EventType=APPCRASH
EventTime=129973086237604286
ReportType=2
Consent=1
ReportIdentifier=91331e8b-2dc8-11e2-977b-080027f7e5bb
IntegratorReportIdentifier=91331e8a-2dc8-11e2-977b-080027f7e5bb
WOW64=1
Response.type=4
Sig[0].Name=Application Name
Sig[0].Value=SAGE_TESTING.vshost.exe
Sig[1].Name=Application Version
Sig[1].Value=10.0.30319.1
Sig[2].Name=Application Timestamp
Sig[2].Value=4ba2084b
Sig[3].Name=Fault Module Name
Sig[3].Value=ntdll.dll
Sig[4].Name=Fault Module Version
Sig[4].Value=6.1.7600.16385
Sig[5].Name=Fault Module Timestamp
Sig[5].Value=4a5bdb3b
Sig[6].Name=Exception Code
Sig[6].Value=c015000f
Sig[7].Name=Exception Offset
Sig[7].Value=000845bb
DynamicSig[1].Name=OS Version
DynamicSig[1].Value=6.1.7600.2.0.0.272.7
DynamicSig[2].Name=Locale ID
DynamicSig[2].Value=2057
DynamicSig[22].Name=Additional Information 1
DynamicSig[22].Value=0a9e
DynamicSig[23].Name=Additional Information 2
DynamicSig[23].Value=0a9e372d3b4ad19135b953a78882e789
DynamicSig[24].Name=Additional Information 3
DynamicSig[24].Value=0a9e
DynamicSig[25].Name=Additional Information 4
DynamicSig[25].Value=0a9e372d3b4ad19135b953a78882e789
Here is the section of code I believe to be causing the exception to be thrown:
//Data from the project linked to the split data
if (oSplitData.Project != null)
{
oProject = oSplitData.Project as SageDataObject190.Project;
oBasicDetail.ProjectID = oProject.ProjectID;
oBasicDetail.ProjectReference = oProject.Reference.ToString();
}
else
{
oBasicDetail.ProjectID = -1;
oBasicDetail.ProjectReference = "NO_PROJECT";
}
To add to all the above I seem to have found that there is a general exception that is being thrown but it doesn't help me out much - if anyone can put some light on this it would be great:
Unhandled exception at 0x78bc7361 in SAGE_TESTING.exe: 0xC0000005: Access violation reading location 0xfeeefeee.
If your program is multi-threaded and the exception is thrown in one of the spawned threads, the Exception may not be caught depending on how you do exception handling in your program.
You can add a catch-all exception handler like this:
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
// Your code here
}
static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine(e.ExceptionObject.ToString());
Environment.Exit(1);
}
}
UPDATE
Based on the code you posted, here are some things to look at
Put a try/catch block around the code you posted.
Are you sure that oSplitData is not null?
In the following line, oProject will be null if oSplitData.Project is not of type SageDataObject190.Project. Test for null.
oProject = oSplitData.Project as SageDataObject190.Project;
You are probably dealing with so-called corrupted state exceptions. These exceptions corrupt the process in a way so it is usually more safe to kill the process since it is very difficult to impossible to recover from such an error, even if it would be only for running a short catch-clause. Examples are StackOverflowExceptions, OutOfMemoryExceptions or AccessViolationExceptions.
There is an extensive and generally interesting explanation on corrupted state exceptions in this article.
What is helpful on getting a hand on such exceptions is to use DebugDiag. With this tool from Microsoft (download on this page) you can define a crash rule which generates a crashdump for your failed process. You can easily open these dump files in Visual Studio, where you may find the source of the exception that lead to the failure. This is not guaranteed but it often helped me in the past to nail down some nasty errors.
Are you invoking non-managed C++ or other code?
I'd try something like
static void Main()
{
try
{
DoSomethingUseful() ;
}
catch ( Exception e )
{
// managed exceptions caught here
}
catch
{
// non-managed C++ or other code can throw non-exception objects
// they are caught here.
}
return ;
}
See Will CLR handle both CLS-Complaint and non-CLS complaint exceptions?
Also C++ try, catch and throw statements at msdn: http://msdn.microsoft.com/en-us/library/6dekhbbc(v=vs.100).aspx
And MSIL opcode throw (0x7A) allows the throwing any object reference. C#, however, does not allow it.
But it looks like they improved things with .Net 2.0 and started wrapping oddball stuff in an RuntimeWrappedException.

How to fix "'System.AggregateException' occurred in mscorlib.dll"

I'm receiving an unhandled exception while debugging, and the program stops executing. The debugger doesn't show me the line so I don't know what to fix.
An unhandled exception of type 'System.AggregateException' occurred in mscorlib.dll
Additional information: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.
Cannot obtain value of local or argument '<this>' as it is not available at this instruction pointer, possibly because it has been optimized away. System.Threading.Tasks.TaskExceptionHolder
How can I troubleshoot this problem?
I also found this question which is pretty similar.
As the message says, you have a task which threw an unhandled exception.
Turn on Break on All Exceptions (Debug, Exceptions) and rerun the program.
This will show you the original exception when it was thrown in the first place.
(comment appended): In VS2015 (or above). Select Debug > Options > Debugging > General and unselect the "Enable Just My Code" option.
You could handle the exception directly so it would not crash your program (catching the AggregateException). You could also look at the Inner Exception, this will give you a more detailed explanation of what went wrong:
try {
// your code
} catch (AggregateException e) {
}
The accepted answer will work if you can easily reproduce the issue. However, as a matter of best practice, you should be catching any exceptions (and logging) that are executed within a task. Otherwise, your application will crash if anything unexpected occurs within the task.
Task.Factory.StartNew(x=>
throw new Exception("I didn't account for this");
)
However, if we do this, at least the application does not crash.
Task.Factory.StartNew(x=>
try {
throw new Exception("I didn't account for this");
}
catch(Exception ex) {
//Log ex
}
)
In my case I ran on this problem while using Edge.js — all the problem was a JavaScript syntax error inside a C# Edge.js function definition.

Categories

Resources