1

I'm writing a C# application (in Linux with mono but it shouldn't matter) and I am programming with duplicati dlls. I want that the program never crashes so I tried to catch every exception. The Problem now is that an exception is thrown and I can't catch it. Maybe from a thread?!?

Sidenote: Just for testing purposes I intentionally tried to backup to a Location where I don't have permission. If I give permission, then I get no error.

The code Looks like the following:

try {
    Interface i = new Interface(backend, options);
    result = i.Backup(folders.ToArray());
} catch (Exception e) {
    //Write to log.
    //Here is no throw; !!
}

I get the following stack trace:

Error : System.Exception: Failed to retrieve file listing: Access to the path "/home/pi/test" is denied. ---> System.UnauthorizedAccessException: Access to the path "/home/pi/test" is denied.
  at System.IO.Directory.GetFileSystemEntries (System.String path, System.String searchPattern, FileAttributes mask, FileAttributes attrs) [0x00000] in <filename unknown>:0
  at System.IO.Directory.GetFiles (System.String path, System.String searchPattern) [0x00000] in <filename unknown>:0
  at System.IO.Directory.GetFiles (System.String path) [0x00000] in <filename unknown>:0
  at Duplicati.Library.Backend.File.List () [0x00000] in <filename unknown>:0
  at Duplicati.Library.Main.BackendWrapper.ListInternal () [0x00000] in <filename unknown>:0
  --- End of inner exception stack trace ---
  at Duplicati.Library.Main.BackendWrapper.ListInternal () [0x00000] in <filename unknown>:0
  at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0

Why am I unable to catch all exceptions? Am I doing something wrong?

Thomas Sparber
  • 2,827
  • 2
  • 18
  • 34
  • 2
    Not directly related: some of exceptions are more exceptional than others - like StackOverflow... Back to question - stack does not really correspond to code shown - so very hard to suggest anything, but indeed exceptions thrown on other thread will not be caught by that code. – Alexei Levenkov Jun 25 '15 at 15:55
  • which line is the error thrown? – laskdjf Jun 25 '15 at 15:56
  • Not all exceptions are recoverable. suppose this exception occurs, it breaks out of your code and goes to the handler. where should your program resume? – CThin Jun 25 '15 at 15:56
  • @AlexeiLenenkov: Ah ok thanks I understand! But here it can't be the stack because my program works when I set the right permissions. So there is no possibility to prevent such a program from crashing?!? – Thomas Sparber Jun 25 '15 at 15:57
  • @FahadJameel: That's the Problem, I can't see it because there is nothing in the stack trace but These lines are the ONLY calls to the library so it must be there – Thomas Sparber Jun 25 '15 at 15:58
  • @CThin: Ok I understand that Point! But if I want to write e.g. a Service application then I can't prevent it from crashing? I can't believe that. – Thomas Sparber Jun 25 '15 at 16:00
  • Well, the idea of forcing an application to continue after any exception is typically seen as a poor decision. That said, I understand that its something you could want. could you simply relaunch an instance of your service in your exception handler? this would prevent bad states from carrying. – CThin Jun 25 '15 at 16:03
  • @CThin: Yes you are right and I know that. The Problem with the relaunch is that it NEVER reaches my exception handler. That's actually my Problem. It just crashes. – Thomas Sparber Jun 25 '15 at 16:06
  • What if you wrap all the code above in a `try/catch`, and don't put anything in the catch? – gunr2171 Jun 25 '15 at 16:35
  • @gunr2171: Sorry, the "do something and write to log" was somehow confusing. I changed it. Actually I don't do anything. I'm just writing to log (stdout) that an error happened. – Thomas Sparber Jun 25 '15 at 16:49

2 Answers2

4
Error : System.Exception: Failed to retrieve file listing: Access to the path...

Well, this is a managed exception and you should be able to catch it, period. Duplicati is using Interop to native libraries, and a failure in that call is where the call stack beings, but it is unwinding and propagating through the managed call stack.

I wrote a really quick Duplicati example and it catches all the exceptions...

No exception:

mono HelloDup.exe "/tmp"
File: Local folder or drive

Exception caught:

ls /home/private/privateinfo
ls: : Permission denied
mono HelloDup.exe "/home/private/privateinfo"
Exception: Access to the path "/home/private/privateinfo" is denied.: Type:System.UnauthorizedAccessException

Exception caught:

mono HelloDup.exe "/foobar"
Exception: The folder /foobar does not exist: Type:Duplicati.Library.Interface.FolderMissingException

Exception caught:

ls -l /noperms/private.txt
--w-------  1 root  wheel  0 Jun 25 14:16 /noperms/private.txt
mono HelloDup.exe "/noperms/private.txt"
Exception: The folder /noperms/private.txt does not exist: Type:Duplicati.Library.Interface.FolderMissingException

Code example:

try {
    var file = new Duplicati.Library.Backend.File(args[0], options);
    file.CreateFolder();
    Console.WriteLine ("File: {0}", file.DisplayName);
} catch (Exception e) {
    Console.WriteLine ("Exception: {0}: Type:{1}", e.Message, e.GetType());
}

Next Steps:

I would check the versions of Mono and Duplicati you are using... If you are a base system install of Mono, you could be really behind the times. Also I used xbuild to compile Duplicati so I'm using the HEAD of the GitHub master branch.

SushiHangover
  • 73,120
  • 10
  • 106
  • 165
  • Thanks for the answer! When I copy your exact code example and Change the path to my Folder than I'm also able to catch the Exception! But NOT when I use the Interface class. I guess the difference here is that by using `Backend.File` the Exception is directly caught but when using `Interface` the exception is thrown in an other thread. – Thomas Sparber Jun 26 '15 at 08:17
  • Interesting. Which version of mono are you using? (mono --version), also which archtecture? x86 or amd64/x86_64? Also interop calling into C vs C++ will result in different exception handing as C does not have exception handing while C++ can, but it is different than managed exception...it gets tricky fast ;-) – SushiHangover Jun 26 '15 at 20:36
  • I'm using mono version 3.2.8. My architecture is ARMv6 (Raspberry :-)) Maybe that's the problem here! Yeah, getting very tricky... – Thomas Sparber Jun 27 '15 at 15:45
2

The catch block is throwing an exception perhaps?

Anyway, A variation of @gunr2171 idea - create a separate Vis. Studio project with a single file (class) and all it does is call the main program wrapped in try/catch; so this is at the very top of the application.

If your library is threaded it should expose a something for testing for a thread-exception; much like the BackgroundWorker.RunWorkerCompleted event.


Register with the AppDomain.UnhandledException event

A simple tutorial


Worthwhile exception catching

Make liberal use of the Exception.Data property. Sometimes I override ToString() in my classes expressly for the purpose of throwing that into Exception.Data.

Catch narrowly as practicable in the body of the application (which it seems the OP has done). This context will help you capture particularly relevant information in Exception.Data. Read the library's - and .NET - documentation.

Have a universal try/catch at the top of the application.

Avoid layers of re-catching that doesn't add context.

Re-Throwing: throw e drops the stack trace up to that point. throw instead.


Make your application robust

  • Define default state. The null object pattern
  • Force clients to use your constructors. Don't expose properties and expect clients to properly initialize. Alan Kay said emphatically that exposing properties (state) is not object oriented programming.
  • I hate null strings. Here is my favorite line of real-live production code: if(string.IsNullOrEmpty(myString.Trim()))

Some hopefully helpful links

Community
  • 1
  • 1
radarbob
  • 4,964
  • 2
  • 23
  • 36