none
C# interop keep throwing MemoryAccessViolation RRS feed

  • Question

  •  

    We have two components, one in C++ and the other in C#. During the process, C++ objects will call C# objects through COM interface.

    At the begining, everything work well. However, as time goes on, more and more exceptions are thrown.

    I can make sure that the C++ code has no memory leak, and of course, C# will not have memory leak.

    Why this happen?

    Is that because .Net runtime has a limit on the stack/heap for interop?

    Or C# release/move some objects, but C++ objects dont know?

     

    Could here anyone give me some help? thank you in advance!

    Saturday, March 1, 2008 11:24 AM

Answers

All replies

  • Is your C# program a WinForm? If so, are you using a Multi Threaded Appartment model (MTA)? If so try it as a STA thread.  My recent experience with Memory Access Violations involved using some TranslateMessage code (in C++) to see if I could determine why my COM was deadlocking.  Show me your code and I'll see if I can help more.

    Sunday, March 2, 2008 12:39 AM
  • To troubleshoot this issue, we really need the source code and the detailed repro steps to reproduce the problem, so that we can investigate the issue in house. It is not necessary that you send out the complete source of your project. We just need a simplest sample to reproduce the problem. You can remove any confidential information or business logic from it.


    Sunday, March 2, 2008 1:08 AM
  • I am sorry for cannot give you the source code. for it is too hard to make a small project that can reproduce the issue.

    But with SEH, I did catch all the exceptions, and protect the application from crashes.

    However, it seems, although it doesnot crash, its internal memory/stack is damaged in someway. Thus we get the following exception, can you help to look into this?

     

    <>First-chance exception at 0x79f1269c in EXCEL.EXE: 0xC0000005: Access violation reading location 0x0000004c.
    <mda:msg xmlns:mda="http://schemas.microsoft.com/CLR/2004/10/mda">
    <!--
    Attempting to call into managed code without transitioning out first. Do not
    attempt to run managed code inside low-level native extensibility points, such
    as the vectored exception handler, since doing so can cause corruption and data
    loss.
    -->
    <mda:reentrancyMsg break="true"/>
    </mda:msg>
    EXCEL.EXE has triggered a breakpoint 

     

    By the way, I heard that the architecture to enable C++ to call C# is not stable. If it is true, how the unstable behave? Is there any fixpack for the CLR?

     

    • Edited by Brent Serbus Thursday, October 30, 2008 7:15 PM style was bad
    Tuesday, March 4, 2008 7:03 AM
  • Maybe you are not releasing memory resources after your objects finnish with what they do.

    Anyway you didn't gave much details so here are some usefull links :


    Documentation
    http://msdn.microsoft.com/library/e...managedcode.asp

    Interop Marshaling
    http://msdn.microsoft.com/library/e...pmarshaling.asp

    Marshaling Data with Platform Invoke
    http://msdn.microsoft.com/library/e...tforminvoke.asp


    and visit this great site:
    http://www.dotnetinterop.com/


    and read this book (COM Interop)
    http://www.amazon.com/exec/obidos/ASIN/067232170X/


    For more, use newsgroup:
    microsoft.public.dotnet.framework.interop

    Tuesday, March 4, 2008 2:18 PM
  • This is an interesting thread. I have a similar problem with a project I'm working on.

     

    My C# application uses interop to connect to a 3rd party application (Enterprise Architect http://www.sparxsystems.com/) and also to connect to Microsoft Word interop.

     

    In Visual Studio debug configuration, the application works correctly. When I build it in release configuration the application throws Access Violation Exceptions, as here:

     

    Attempted to read or write protected memory. this is often an indication that other memory is corrupt
    Error caused by CustomMarshalers
    at VariantClear(tagVARIANT* pvarg
    at System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant.MoveNext at EAReportWriter.UseCase.DumpPackageUseCase(Package package)
    at EAReportWriter.UseCase.OpenUseCase(String DocName, String PackName, String IntroTxt, INT65 packageID)
    at EAReportWriter.formWordReport.RunButton_Click(Object sender, EventArgs e)

    The EAReportWriter part is my stuff. I haven't been able to pin down exactly where the exception is being thrown in my C# code. I've tried putting try/catch blocks around progressively smaller blocks of code to find out where the exceptions are coming from, but they don't catch anything interesting. I've also tried putting trace statements to output messages to a file, but they seem to affect execution the same way that building in debug configuration does, so sometimes with enough trace statements it doesn't crash.

     

    The closest I've been able to come to narrowing the problem is a foreach loop where execution has just completed one loop and is starting the next. I've collected an arraylist of EA objects and am iterating through them to process each with the foreach loop. The objects are valid when they're put in the arraylist, though I'm sorting the list and I don't know if that could be where the problem is arising. Of course I have to also consider that it could be a bug in EA. Maybe I should bring them in on the problem.

     

    I'm mostly hoping to find out some techniques to find where the problem lies. The tools I'm trying right now won't do it since they're affecting the outcome. I suspect a race condition, since results seem to be affected by debug, trace, and what kind of computer it's running on.

     

    Also, there seems to be no problem with the Word Interop connection. That part seems to execute properly. Word captures complete text up to the point where the exception occurs and the C# and EA applications are closed.

     

    Being pressed for time, I've made an interim release (for internal use) of the application in debug configuration. I'd like to find out how to release it in release configuration without having it crash. I don't know if I'll be able to post code snippets since I won't know what snippets to post without narrowing the problem some more.

    Tuesday, March 4, 2008 5:25 PM
  • As I understand it would be usefull if you can track down which line of code exactly trows exception in C# code. I found this text on web address:

     

    http://forums.sqladvice.com/post.aspx?id=7285

     

    here it is:

     

    Did you know that depending on the way you rethrow exceptions you may lose important information? There are already several blog posts that explain and demonstrate the difference between throw and throw ex. I'm realizing only now that none of the two solutions yields the complete call stack trace information!

    Let's see what the problem is and I'll show you the real solution.

    I'll use the following method to generate an exception:

    private static void BadWork()
    {
      int i = 0;
      int j = 12 / i; // Line 10: DivideByZeroException
      int k = j + 1;
    }

    Let's consider what happens if we call BadWork and rethrow the exception with throw ex as follows:

    try
    {
      BadWork();
    }
    catch (Exception ex)
    {
      // do something
      // ...
      throw ex; // Line 24
    }

    Here is the call stack trace that we get in this case:

    Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
       at Program.WithThrowEx() in Program.cs:line 24
       at Program.Main(String[] args) in Program.cs:line 88

    Line 24 is where throw ex is, not where the exception was thrown.

    Let's now replace throw ex by throw:

    try
    {
      BadWork();
    }
    catch
    {
      // do something
      // ...
      throw; // Line 38
    }


    This time, here is the call stack trace:

    Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
       at Program.BadWork() in Program.cs:line 10
       at Program.WithThrow() in Program.cs:line 38
       at Program.Main(String[] args) in Program.cs:line 89

    As you can see, we get one additional stack frame this time. Line 10 is where the exception was thrown, which is important information because this is the only information that identifies where the exception actually happened.

    This shows that it's better to use throw rather than throw ex if you want the full stack trace information to be preserved. However, there are cases where throw is not enough. In the following example, throw does not preserve the full stack trace:

    try
    {
      int i = 0;
      int j = 12 / i; // Line 47
      int k = j + 1;
    }
    catch
    {
      // do something
      // ...
      throw; // Line 54
    }

    Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
       at Program.WithThrowIncomplete() in Program.cs:line 54
       at Program.Main(String[] args) in Program.cs:line 106

    This time, you can see that information is lost again. Line 54 is where throw is, not where the exception was thrown.

    To preserve the full call stack information, you need to use the following method:

    private static void PreserveStackTrace(Exception exception)
    {
      MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
        BindingFlags.Instance | BindingFlags.NonPublic);
      preserveStackTrace.Invoke(exception, null);
    }

    This method can be used as follows: 

    try
    {
      int i = 0;
      int j = 12 / i; // Line 78
      int k = j + 1;
    }
    catch (Exception ex)
    {
      // do something
      // ...
      PreserveStackTrace(ex);
      throw; // Line 86
    }

    Here is the new call stack information you get with the above code:

    Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
       at Program.WithThrowAndStackTracePreservation() in Program.cs:line 78
       at Program.WithThrowAndStackTracePreservation() in Program.cs:line 86
       at Program.Main(String[] args) in Program.cs:line 110

    Here is the call stack information you get with throw ex and a call to PreserveStackTrace:

    Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
       at Program.BadWork() in Program.cs:line 10
       at Program.WithThrowExAndStackTracePreservation() in Program.cs:line 62
       at Program.WithThrowExAndStackTracePreservation() in Program.cs:line 69
       at Program.Main(String[] args) in Program.cs:line 109

    Here we get the full call stack information. Lines 78 and 10 are where the exceptions were thrown. To my knowledge, this is the only way to get complete call stack information in your logs. Without it, it may be difficult to hunt down some bugs.
    It's worth noting that if you call PreserveStackTrace, then you can use throw or throw ex and you'll equally get the full stack trace information.

    I found this useful trick on Chris Taylor's blog. If you want to use this with .NET 1, you should refer to Chris' post because it seems that the InternalPreserveStackTrace method didn't exist before .NET 2.0.

    The complete source code is attached to this post.

     

    Wednesday, March 5, 2008 8:17 AM
  • That is interesting. However, I found that it didn't give me any more information in the stack trace than before. That may be because I'm trying to capture the stack trace with the application built in release configuration rather than debug configuration. I suspect that the information just isn't there.

     

    What would really interest me is knowing what makes the release configuration different from the debug configuration so that the release configuration crashes while the debug version doesn't. As nearly as I can tell, there are two differences: The debug version has optimization turned off and has debug info turned on to full. In the release configuration, I tried turning off optimization and that made no difference at all--it still crashed. But when I turned on debug info, that made the difference. In the debug configuration, I tried changing the same two items and it was the debug info that makes it not crash. Why?

     

    What would be the harm in releasing a debug version of the software (this is a dll). Is the debug configuration covering up some major bug? If so I'd really like to find it and fix it. So how can I get the application to throw a access violation exception while it's running in the VS debugger, where I can see what's going on?

     

     

    Wednesday, March 5, 2008 4:55 PM
  • If you go to properties of solution, where you can set level of error, or something like that, you can see that you can have (I am not sure 4 levels), and in level 4 even warnings are treated like errors.

    So you see, probably release assume that level of compiling is top level 4 where even warnings are treated like errors.

    release can't have any flaw Smile

    greet
    Wednesday, March 5, 2008 9:07 PM
  •  

    I think that only covers compiler errors. You can filter compiler warnings that aren't important, like vestigial variables that you declared but never used. It's set at 4 by default for both debug and release.

     

    I may have made some progress in my debugging efforts. I happened to try putting a try/catch around a recursive call with a foreach loop. A snippet:

    try

    {

    void DumpPackageUseCase(Package package)

    {

    // Some processing stuff

    foreach (Package objPackage in package.Packages)

    {

    DumpPackageUseCase(objPackage);

    }

    }

    }

     

    In release mode, this code is throwing random access violations. It works most of the time but occasionally, at unpredictable points, it fails. Package in this case is part of a COM reference. Apparently that COM reference accounts for the part of the exception stack trace:

     

    at VariantClear(tagVARIANT* pvarg)

    at System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant.MoveNext()

    ...

     

    It looks like EnumeratorViewOfEnumVariant is part of InteropServices' COM implementation of IEnumerable, which allows me to use foreach, though I can't seem to find much information about it. In any case, it's part of the framework, beyond my meddling. Don't know if the recursion could also be related somehow.

     

     

    Wednesday, March 5, 2008 9:26 PM
  • Yep, that hypothesis is correct. I can't use foreach for this loop. I just switched that snippet to

    this code and get no more access violations:

     

    for (short i = 0; i < package.Packages.Count; i++)

    {

    EA.Package thisPackage = (EA.Package)package.Packages.GetAt(i);

    DumpPackageUseCase(thisPackage);

    }

     

    I think I've found my solution. I'll just need to implement something like it in some other branches of my code.

    • Proposed as answer by KittyCute Thursday, October 30, 2008 12:11 PM
    Wednesday, March 5, 2008 9:47 PM
  • Hi rkhenry!!

    You save my life !! Thank you soooo much...
    Thanks for sharing the solution for such this error.
    I have the similar problem with you and searching for the solution for about 2 weeks (whew), and now it resolved.
    I develop an Add-In for Sparx Enterprise Architect too. And I also got the error like yours:

    Attempted to read or write protected memory. this is often an indication that other memory is corrupt

    With the top most stack is :

     at System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant.MoveNext()

    My code was something like below :


    private void iterate(EA.Element element, XmlSchema schema, bool isRoot) 
        ............ 
        foreach (EA.Connector con in element.Connectors) 
        { 
            if (con.Type.ToString() == EA_Element.Aggregation.ToString() && 
                con.Stereotype.ToString() == CCTS_Types.ASBIE.ToString()) 
            { 
                ......... 
                iterate(client, schema, false); 
            } 
        } 
    }  



    and I changed it into these :


    private void iterate(EA.Element element, XmlSchema schema, bool isRoot) 
        ......... 
        for (short a = 0; a < element.Connectors.Count; a++) 
        { 
            EA.Connector con = (EA.Connector)element.Connectors.GetAt(a); 
            if (con.Type.ToString() == EA_Element.Aggregation.ToString() && 
                con.Stereotype.ToString() == CCTS_Types.ASBIE.ToString()) 
            { 
                ......... 
                iterate(client, schema, false); 
            } 
        } 
    }  



    My conclusion, we can't have any recursive method inside "foreach" loop. BUT the next question is, is my conclusion only valid for collection from Sparx Enterprise Architect OR all collection in .net??

    Thanks all.


    Cheers.

    Thursday, October 30, 2008 10:16 AM
  • Thank you very much, R. Henry, for posting your progress online! I had the exact same problem with EA! Even though I found that it must have to do with the foreach, I did not think of using a normal for loop until I googled and found your post.

    Tuesday, September 1, 2009 2:48 PM
  • I wrote a blog to make sure that others will find this solution, too (since the EA community is not really too large...): http://darkroastjava.wordpress.com/2009/09/01/enterprise-architect-beware-of-for-each-loops/

    Tuesday, September 1, 2009 3:35 PM
  • I have the same problem but i can't use the for loop since i dont have GetAt() function. How do i implemente it?

    Cheers
    Thursday, September 24, 2009 9:17 AM
  • This fixed my problem as well. I'm also developing an Add-In in EA. Thanks for posting.
    Wednesday, February 2, 2011 10:30 PM