Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle AccessViolationException

I am using a COM object (MODI) from within my .net application. The method I am calling throws a System.AccessViolationException, which is intercepted by Visual Studio. The odd thing is that I have wrapped my call in a try catch, which has handlers for AccessViolationException, COMException and everything else, but when Visual Studio (2010) intercepts the AccessViolationException, the debugger breaks on the method call (doc.OCR), and if I step through, it continues to the next line instead of entering the catch block. Additionally, if I run this outside of the visual studio my application crashes. How can I handle this exception that is thrown within the COM object?

MODI.Document doc = new MODI.Document();
try
{
    doc.Create(sFileName);
    try
    {
        doc.OCR(MODI.MiLANGUAGES.miLANG_ENGLISH, false, false);
        sText = doc.Images[0].Layout.Text;
    }
    catch (System.AccessViolationException ex)
    {
        //MODI seems to get access violations for some reason, but is still able to return the OCR text.
        sText = doc.Images[0].Layout.Text;
    }
    catch (System.Runtime.InteropServices.COMException ex)
    {
        //if no text exists, the engine throws an exception.
        sText = "";
    }
    catch
    {
        sText = "";
    }

    if (sText != null)
    {
        sText = sText.Trim();
    }
}
finally
{
    doc.Close(false);

    //Cleanup routine, this is how we are able to delete files used by MODI.
    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(doc);
    doc = null;
    GC.WaitForPendingFinalizers();
    GC.Collect();
    GC.WaitForPendingFinalizers();

}
like image 821
Jeremy Avatar asked Aug 12 '10 15:08

Jeremy


People also ask

How to handle access Violation exception c#?

To handle such an AccessViolationException exception, apply the HandleProcessCorruptedStateExceptionsAttribute attribute to the method in which the exception is thrown. This change does not affect AccessViolationException exceptions thrown by user code, which can continue to be caught by a catch statement.

What is a system AccessViolationException?

A System. AccessViolationException occurs when unmanaged/unsafe code attempts to use memory that has not been allocated, or to memory that it doesn't have access to.


4 Answers

EDIT (3/17/2021)

Disclaimer: This answer was written in 2011 and references the original .NET Framework 4.0 implementation, NOT the open-source implementation of .NET.


In .NET 4.0, the runtime handles certain exceptions raised as Windows Structured Error Handling (SEH) errors as indicators of Corrupted State. These Corrupted State Exceptions (CSE) are not allowed to be caught by your standard managed code. I won't get into the why's or how's here. Read this article about CSE's in the .NET 4.0 Framework:

http://msdn.microsoft.com/en-us/magazine/dd419661.aspx#id0070035

But there is hope. There are a few ways to get around this:

  1. Recompile as a .NET 3.5 assembly and run it in .NET 4.0.

  2. Add a line to your application's config file under the configuration/runtime element: <legacyCorruptedStateExceptionsPolicy enabled="true|false"/>

  3. Decorate the methods you want to catch these exceptions in with the HandleProcessCorruptedStateExceptions attribute. See http://msdn.microsoft.com/en-us/magazine/dd419661.aspx#id0070035 for details.


EDIT

Previously, I referenced a forum post for additional details. But since Microsoft Connect has been retired, here are the additional details in case you're interested:

From Gaurav Khanna, a developer from the Microsoft CLR Team

This behaviour is by design due to a feature of CLR 4.0 called Corrupted State Exceptions. Simply put, managed code shouldnt make an attempt to catch exceptions that indicate corrupted process state and AV is one of them.

He then goes on to reference the documentation on the HandleProcessCorruptedStateExceptionsAttribute and the above article. Suffice to say, it's definitely worth a read if you're considering catching these types of exceptions.

like image 179
villecoder Avatar answered Oct 01 '22 12:10

villecoder


Add the following in the config file, and it will be caught in try catch block. Word of caution... try to avoid this situation, as this means some kind of violation is happening.

<configuration>
   <runtime>
      <legacyCorruptedStateExceptionsPolicy enabled="true" />
   </runtime>
</configuration>
like image 28
Partha Avatar answered Oct 01 '22 12:10

Partha


Compiled from above answers, worked for me, did following steps to catch it.

Step #1 - Add following snippet to config file

<configuration>
   <runtime>
      <legacyCorruptedStateExceptionsPolicy enabled="true" />
   </runtime>
</configuration>

Step #2

Add -

[HandleProcessCorruptedStateExceptions]

[SecurityCritical]

on the top of function you are tying catch the exception

source: http://www.gisremotesensing.com/2017/03/catch-exception-attempted-to-read-or.html

like image 44
EvilInside Avatar answered Oct 01 '22 14:10

EvilInside


Microsoft: "Corrupted process state exceptions are exceptions that indicate that the state of a process has been corrupted. We do not recommend executing your application in this state.....If you are absolutely sure that you want to maintain your handling of these exceptions, you must apply the HandleProcessCorruptedStateExceptionsAttribute attribute"

Microsoft: "Use application domains to isolate tasks that might bring down a process."

The program below will protect your main application/thread from unrecoverable failures without risks associated with use of HandleProcessCorruptedStateExceptions and <legacyCorruptedStateExceptionsPolicy>

public class BoundaryLessExecHelper : MarshalByRefObject
{
    public void DoSomething(MethodParams parms, Action action)
    {
        if (action != null)
            action();
        parms.BeenThere = true; // example of return value
    }
}

public struct MethodParams
{
    public bool BeenThere { get; set; }
}

class Program
{
    static void InvokeCse()
    {
        IntPtr ptr = new IntPtr(123);
        System.Runtime.InteropServices.Marshal.StructureToPtr(123, ptr, true);
    }

    private static void ExecInThisDomain()
    {
        try
        {
            var o = new BoundaryLessExecHelper();
            var p = new MethodParams() { BeenThere = false };
            Console.WriteLine("Before call");

            o.DoSomething(p, CausesAccessViolation);
            Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); //never stops here
        }
        catch (Exception exc)
        {
            Console.WriteLine($"CSE: {exc.ToString()}");
        }
        Console.ReadLine();
    }


    private static void ExecInAnotherDomain()
    {
        AppDomain dom = null;

        try
        {
            dom = AppDomain.CreateDomain("newDomain");
            var p = new MethodParams() { BeenThere = false };
            var o = (BoundaryLessExecHelper)dom.CreateInstanceAndUnwrap(typeof(BoundaryLessExecHelper).Assembly.FullName, typeof(BoundaryLessExecHelper).FullName);         
            Console.WriteLine("Before call");

            o.DoSomething(p, CausesAccessViolation);
            Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); // never gets to here
        }
        catch (Exception exc)
        {
            Console.WriteLine($"CSE: {exc.ToString()}");
        }
        finally
        {
            AppDomain.Unload(dom);
        }

        Console.ReadLine();
    }


    static void Main(string[] args)
    {
        ExecInAnotherDomain(); // this will not break app
        ExecInThisDomain();  // this will
    }
}
like image 23
T.S. Avatar answered Oct 01 '22 13:10

T.S.