2

I am trying to log an exception using the Exception.ToString() method. However, I get a new exception from the ToString() method - it seems to originate from the stack trace handling. The original error is a FileNotFoundException. Here is the output:

The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileNotFoundException
   at System.Signature.GetSignature(Void*, Int32, System.RuntimeFieldHandleInternal, System.IRuntimeMethodInfo, System.RuntimeType)
   at System.Reflection.RuntimeMethodInfo.FetchNonReturnParameters()
   at System.Reflection.RuntimeMethodInfo.GetParameters()
   at System.Diagnostics.StackTrace.ToString(TraceFormat)
   at System.Environment.GetStackTrace(System.Exception, Boolean)
   at System.Exception.GetStackTrace(Boolean)
   at System.Exception.get_StackTrace()
   at System.IO.FileNotFoundException.ToString()
   at InSQLMDASDriver.InSQLMDASDriver.Init(System.String, System.String)
   at InSQLMDASDriver.InSQLMDASDriverLogic.InSQLMDASDriverLogicInit(System.String, System.String)
   at InSQLMDASDriver.InSQLMDASDriverLogic..ctor(System.String, System.String)
   at InSQLMDASDriverWCFServer.Service1.MainTread()
   at System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.ThreadHelper.ThreadStart()

When I run this code I can verify that the exception is thrown from Exception.ToString():

    private void Init(string defaultWindowName, string mainPath)
    {    
       try 
       {

            // code that fails

        }
        catch(FileNotFoundException e)
        {
             string errorAsString = GetErrorAsString(e);

             Logger.Log(string.Format("Init error at line block {0}: {1}", initBlockCounter, errorAsString), level: LogLevel.Error);


             throw new Exception("FileNotFoundException: " + e.FileName + ", " + e.FusionLog, e);
       }
       catch (Exception e)
       {
              string errorAsString = GetErrorAsString(e);

              Logger.Log(string.Format("Init error at line block {0}: {1}", initBlockCounter, errorAsString), level: LogLevel.Error);


          throw;
      }
}

    string GetErrorAsString(Exception e)
    {
         try
         {
             return e.ToString();
         }
         catch(Exception ne)
         {
                     return e.Message + " (ERROR getting stacktrace: " + ne.Message + ")";
          }
    }

Why does this happen..?

Rye bread
  • 1,305
  • 2
  • 13
  • 36
  • Can you show us the code that calls `GetErrorAsString` ? – Jens Meinecke Jun 06 '17 at 10:30
  • 1
    Can you show that exception? But at first glance, it might be due to the e object being null. check it. – Renato Afonso Jun 06 '17 at 10:31
  • @RenatoAfonso - if that were the case the `e.Message` reference in the `catch(Exception ne)` part would cause a re-throw again... – Jens Meinecke Jun 06 '17 at 10:32
  • And that exactly might be the case where he has the error. His own ToString is going to the catch. – Renato Afonso Jun 06 '17 at 10:37
  • Try removing some of the noise. You are rethrowing exceptions and doing a lot of work that is not core to your question. How much can you remove without changing the behaviour? – Iain Ballard Jun 06 '17 at 10:44
  • 1
    According to the stacktrace your code never reaches `GetErrorAsString()`. `Exception.ToString()` will not throw `FileNotFoundException` in any case. – Guy Jun 06 '17 at 10:54
  • GetErrorAsString() was added after the original problem to try to find out what was going on. I haven't posted the output from that method yet. – Rye bread Jun 06 '17 at 10:59
  • 1
    I'm guessing the runtime is trying to load an assembly that it cannot find during the creation of the stack trace. Can you show us the Message of the FileNotFoundException? – Jonas Høgh Jun 06 '17 at 11:13
  • @user1919998 Please do. As well as the complete `Init` method. – Guy Jun 06 '17 at 11:14

1 Answers1

3

Here is a description that matches my issue where an assembly failing to load causes a FileNotFoundException, and calling ToString() gives another exception:

Here is what happens. The Newtonsoft.Json.JsonConvert.DeserializeObject needs System.Runtime.Serialization.Primitives assembly. But it is not present, so it tries to throw the FileNotFoundException. It creates the exception object and then it wants to set the stack trace for it. So it looks at the topmost frame of the exception stack trace, finds the Newtonsoft.Json.JsonConvert.DeserializeObject method there and tries to use reflection to get its parameters info. When looking at the 2nd parameter of the method which is of type Newtonsoft.Json.JsonSerializerSettings, it tries to build the metadata structure for this parameter type. And accidentally, one of the fields of this type is of the StreamingContext type that comes from the System.Runtime.Serialization.Primitives assembly. To get details on the type, it attempts to load this assembly - and since it doesn't exist (that was the reason for the original exception we are trying to build stack trace for), it throws an exception and the result is what you can see.

See the bug report and discussion there: https://github.com/dotnet/runtime/issues/5203. It should be fixed meanwhile.

Abel
  • 56,041
  • 24
  • 146
  • 247
Rye bread
  • 1,305
  • 2
  • 13
  • 36