Can an internal clr exception be caught and retried?

0

While calling .ToArray, I am hitting the following exception:

Internal CLR error. (0x80131506)
at System.Linq.Enumerable.ToArray[[System.__Canon, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.Collections.Generic.IEnumerable`1<System.__Canon>)

This happens intermittently, and is hard to reproduce. Can this type of exception be caught and retried? Would I just have to catch a generic exception.

The code to call .ToArray() is inside an async Task. There is already a general try/catch outside the async code to catch any exception and log it. It does not seem to be getting to that code (as evidenced by the fact that the log message is not printed)

Unfortunately, I don't have a good small reproducible example. If I had one, I could probably debug and find out what the issue is. It happens maybe 1% of the time.

The generic structure looks like:

private async Task<bool> Foo()
{
    try
    {
      return (await Bar()).Value;
    }
    catch (Exception e)
    {
       LogError();
       return false;
    }
}

private async Task<bool> Bar()
{
    // workQueue uses an ActionBlock to run tasks
    var tasks = workToDo.Select(item => await workQueue.ProcessItem(item, DoWorkOnItem));
    await Task.WhenAll(tasks);
}

async Task<bool> DoWorkOnItem(Item i)
{
    var convertedStatements = i.Select(s => ConvertStatement(s, context)).Where(s => s != null).ToList();
    var statementArray = ConvertedStatement.FlattenStatements(convertedStatements).ToArray(); // This is where the exception is hit
}

public static IList<Statement> FlattenStatements(ICollection<ConvertedStatement> convertedStatements)
{
    Contract.Requires(convertedStatements != null);

     var result = new List<Statement>(convertedStatements.Count);
     foreach (var statement in convertedStatements)
     {
         // m_statement is only set in the constructor of Statement
         if (statement.m_statement != null)
         {
             result.Add(statement.m_statement);
         }
         else
         {
             // m_statements is a read-only list of Statement, only set in the constructor of Statement
             result.AddRange(statement.m_statements);
         }
     }

     return result;
}

Should I be adding a try catch inside the queued task? When it prints the full exception of the internal CLR error, that trace does not include Foo(), it goes up throw the action block like this:

 at BuildXL.FrontEnd.Sdk.SourceFileProcessingQueue`1[[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ProcessWorkItem(QueueInput`1<Boolean,Boolean>)
 at System.Threading.Tasks.Dataflow.ActionBlock`1[[BuildXL.FrontEnd.Sdk.SourceFileProcessingQueue`1+QueueInput`1[[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], BuildXL.FrontEnd.Sdk, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6212d9137135ce5d]].ProcessMessageWithTask(System.Func`2<QueueInput`1<Boolean,Boolean>,System.Threading.Tasks.Task>, System.Collections.Generic.KeyValuePair`2<QueueInput`1<Boolean,Boolean>,Int64>)
 at System.Threading.Tasks.Dataflow.ActionBlock`1+<>c__DisplayClass6_1[[BuildXL.FrontEnd.Sdk.SourceFileProcessingQueue`1+QueueInput`1[[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], BuildXL.FrontEnd.Sdk, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6212d9137135ce5d]].<.ctor>b__2(System.Collections.Generic.KeyValuePair`2<QueueInput`1<Boolean,Boolean>,Int64>)
 at System.Threading.Tasks.Dataflow.Internal.TargetCore`1[[BuildXL.FrontEnd.Sdk.SourceFileProcessingQueue`1+QueueInput`1[[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], BuildXL.FrontEnd.Sdk, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6212d9137135ce5d]].ProcessMessagesLoopCore()
 at System.Threading.Tasks.Task.InnerInvoke()
 at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
 at System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread)
 at System.Threading.ThreadPoolWorkQueue.Dispatch()

That makes me think the try catch should be in DoWorkOnItem, not Foo. Does that sound right?

c#
exception
.net-core
asked on Stack Overflow Sep 11, 2019 by user2460953 • edited Sep 11, 2019 by user2460953

1 Answer

0

This looks like a legit internal error. If you search for the error code you'll find instances of this appearing, followed by fixes by Microsoft.

Can an internal clr exception be caught and retried?

I'm curious, have you tried it? What was your result?

This isn't a FileNotFoundException, which you might correctly think you could retry. It's problematic, as you don't know how badly the CLR/execution engine's internal state might be damaged. Retrying could get you another exception, or merely incorrect results.

In short, if you're using the latest release, the right thing to do is probably to report it to Microsoft.

answered on Stack Overflow Sep 11, 2019 by Curt Nichols

User contributions licensed under CC BY-SA 3.0