C# try/catch/finally
-
So, let's say I'm in a catch block and determine that the exception I'm handling actually means everything is fucked forever and I need to terminate the whole goddamn process tree.
So I throw an exception that will not be caught upstream. Does my finally still execute or should I explicitly clean up before I throw my new exception?
Yes, this is a dirty awful hack.
-
A bit of experimentation suggests the finally is run before any catch handling. Here's a simple .net fiddle
-
@Weng Finally blocks always execute.
-
@mott555 said in C# try/catch/finally:
@Weng Finally blocks always execute.
Not with a try/finally when try throws an unhandled exception.
Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up.
-
This is also often implemented using IDisposable and a using block, which is essentially a try/finally, but with a more normal design for cleaning something up.
-
@Jaloopa For some reason, actually trying it never occurred to me
-
@Jaloopa said in C# try/catch/finally:
A bit of experimentation suggests the finally is run before any catch handling. Here's a simple .net fiddle
If you think that empirical observation is as good as contractually defined behavior, you should read more Raymond Chen.
-
@error if enough people rely on the side effects they become de facto contractual
-
@Jaloopa said in C# try/catch/finally:
@error if enough people rely on the side effects they become de facto contractual
And Raymond will hate you for it. One day he's going to snap, hunt you down and force you to debug poorly written code.
-
@Medinoc said in C# try/catch/finally:
@Jaloopa said in C# try/catch/finally:
@error if enough people rely on the side effects they become de facto contractual
And Raymond will hate you for it. One day he's going to snap, hunt you down and force you to debug poorly written code.
In assembly, without debugging symbols, on software from 30 years ago whose source code has been missing for decades.
-
@mott555 said in C# try/catch/finally:
@Weng Finally blocks always execute.
Except in case of nuclear armageddon.
Or thread death in general.
-
@error said in C# try/catch/finally:
If you think that empirical observation is as good as contractually defined behavior
The prevalent problem is that the contractual behaviour is promised but not fulfilled, which you can only discover by empirical observation.
-
@Jaloopa said in C# try/catch/finally:
A bit of experimentation suggests the finally is run before any catch handling. Here's a simple .net fiddle
Now put a
Console.WriteLine("Finally 3");
Before your
throw new Exception("level1");
Generally, finally block executes after the catch but before an unhandled exception is thrown.
You obviously can crash the application from within an arbitrary place in code, just useJust checked it, it still allows finally's to run.Environment.Exit(0)
, IIRC.ETA
`Environment.FailFast("crash and burn") seems to be able to skip finally's. At least that's what MSDN says.
ETA 2
Yup, just checked it. It will execute everything up to the
FailFast()
call and then crash and burn ('FatalExecutionEngineError').
-
@kt_ Probably an InvalidProgramException, and certainly a StackOverflowException or OutOfMemoryException will do this.
-
@Magus said in C# try/catch/finally:
@kt_ Probably an InvalidProgramException, and certainly a StackOverflowException or OutOfMemoryException will do this.
Or pulling the plug.
-
@kt_ said in C# try/catch/finally:
Before your throw new Exception("level1");
And you know, somewhere up the stack, some idiot has
... catch(Exception) { // Prevent program from crashing - eat it. }
-
@dcon said in C# try/catch/finally:
@kt_ said in C# try/catch/finally:
Before your throw new Exception("level1");
And you know, somewhere up the stack, some idiot has
... catch(Exception) { // Prevent program from crashing - eat it. }
I'm currently Googling how to stop ASP's default handling for this exact reason.
I just want to return a 400 with a small string, not a "Hey, this site's dev didn't enable custom errors, and we were told not to do things with that error code, so we're splatting an ugly Web 1.0 error page for you! How nice of us!" page.
Edit: Also:
-
@dcon said in C# try/catch/finally:
@kt_ said in C# try/catch/finally:
Before your throw new Exception("level1");
And you know, somewhere up the stack, some idiot has
... catch(Exception) { // Prevent program from crashing - eat it. }
That's actually the catch block I'm editing.
-
public void Brillant() { try { Brillant(); } catch(StackOverflowException) { Brillant(); } }
-
@Magus said in C# try/catch/finally:
@kt_ Probably an InvalidProgramException, and certainly a StackOverflowException or OutOfMemoryException will do this.
Outofmemoryexception can be caught and handled. I've caught them before, popped up a message box saying "don't do that" and continued with the memory hog taken out of scope.
-
@Jaloopa There's official documentation saying that while it may sometimes be possible, it isn't terribly trustworthy, iirc. I imagine it works more often than they told me, but I still wouldn't trust it.
-
@kt_ said in C# try/catch/finally:
@Magus said in C# try/catch/finally:
@kt_ Probably an InvalidProgramException, and certainly a StackOverflowException or OutOfMemoryException will do this.
Or pulling the plug.
Yeah, if you're relying on the finally blocks executing in termination scenarios, you're going to be in trouble once someone kills your app from Task Manager or something like this.
-
@Magus yeah, I wouldn't normally rely on it being catchable but this was a bit of a special case and basically meant the user wasn't going to be able to do what they were trying. If the whole app died, it wasn't much different from getting the message except a bit less friendly
-
@Maciejasjmj said in C# try/catch/finally:
@kt_ said in C# try/catch/finally:
@Magus said in C# try/catch/finally:
@kt_ Probably an InvalidProgramException, and certainly a StackOverflowException or OutOfMemoryException will do this.
Or pulling the plug.
Yeah, if you're relying on the finally blocks executing in termination scenarios, you're going to be in trouble once someone kills your app from Task Manager or something like this.
Which means you should always write your app in a way that makes this type of shutdown safe.
Another thing is, I can't really think about a scenario where you'd want an application to shut down without calling the finally blocks.
Still, I've never worked with serious data. Just credit card information, health-related data, PII and detailed insurance history.
-
@dcon said in C# try/catch/finally:
@kt_ said in C# try/catch/finally:
Before your throw new Exception("level1");
And you know, somewhere up the stack, some idiot has
... catch(Exception) { // Prevent program from crashing - eat it. }
I don't really understand what your point is, but mine was that it will be printed before the writeline in finally but before the exception is thrown.
Funny thing, C# is.
-
@kt_ said in C# try/catch/finally:
@dcon said in C# try/catch/finally:
@kt_ said in C# try/catch/finally:
Before your throw new Exception("level1");
And you know, somewhere up the stack, some idiot has
... catch(Exception) { // Prevent program from crashing - eat it. }
I don't really understand what your point is, but mine was that it will be printed before the writeline in finally but before the exception is thrown.
Funny thing, C# is.
I was pointing out that somewhere up the call stack, the odds are high someone is trying to suppress all exceptions. So throwing one may not do what you want. From @Weng 's response, I'm assuming he's attacking this at that higher place (my response was assuming it was lower in the stack and that that suppression may be happening higher, unbeknownst to him)
-
@Zecc said in C# try/catch/finally:
@mott555 said in C# try/catch/finally:
@Weng Finally blocks always execute.
Except in case of nuclear armageddon.
Or thread death in general.
Every time I see "this code always runs", I think "what happens if the janitor unplugs the server so they can vacuum?"
-
@dcon said in C# try/catch/finally:
@kt_ said in C# try/catch/finally:
@dcon said in C# try/catch/finally:
@kt_ said in C# try/catch/finally:
Before your throw new Exception("level1");
And you know, somewhere up the stack, some idiot has
... catch(Exception) { // Prevent program from crashing - eat it. }
I don't really understand what your point is, but mine was that it will be printed before the writeline in finally but before the exception is thrown.
Funny thing, C# is.
I was pointing out that somewhere up the call stack, the odds are high someone is trying to suppress all exceptions. So throwing one may not do what you want. From @Weng 's response, I'm assuming he's attacking this at that higher place (my response was assuming it was lower in the stack and that that suppression may be happening higher, unbeknownst to him)
That's why simple
Environment.Exit(0)
should be enough. Let those finally blocks execute, just don't allow any exception be suppressed.
-
@kt_ said in C# try/catch/finally:
That's why simple Environment.Exit(0) should be enough.
You probably shouldn't be putting a 0 here if it's an abnormal situation. And @Weng might want, say, a global exception handler to run.
-
@Magus said in C# try/catch/finally:
There's official documentation saying that while it may sometimes be possible, it isn't terribly trustworthy, iirc. I imagine it works more often than they told me, but I still wouldn't trust it.
It depends on whether the allocation that failed was large or small. You can usually recover from a failing large allocation — that 2GB image buffer not available? I can still pop up a dialog to tell the user about the problem — whereas you're up shit creek if a small allocation throws since virtually any recovery strategy will require you to allocate more memory, which you can no longer safely do even a little bit of in general…
-
@dkf said in C# try/catch/finally:
virtually any recovery strategy will require you to allocate more memory,
Allocate error handler memory at the start of the app and hold on to it in case it needs it for error recovery?
But, that just sounds wasteful...
-
@Tsaukpaetra said in C# try/catch/finally:
Allocate error handler memory at the start of the app and hold on to it in case it needs it for error recovery?
But then you could have just not allocated it and continued on without the failure in the first place; the strategy to recover helped cause the failure. There really isn't a good alternative to actually not leaking memory in the first place; even garbage collection isn't a silver bullet for this, since you just get leaks then from unexpectedly-retained references. (OTOH, it helps in other ways since it at least stops you from having values pulled out from under your references' feet.)
-
If you're a function in an arbitrary program, you cannot ensure both of these happen:
- Run finally/defer/whatever your language of choice has for everything in the call stack
- Exit the process
You can either do an exit syscall or throw an exception/panic. As long as the finally block can execute code, it can jump straight back into the program's main loop.
-
@mott555 said in C# try/catch/finally:
In assembly, without debugging symbols, on software from 30 years ago whose source code has been missing for decades.
Softcore.
In my day we used red pens to debug octal dumps on fifteen inch greenbar, and we liked it.
-
@flabdablet said in C# try/catch/finally:
octal dumps
@flabdablet said in C# try/catch/finally:
and we liked it.
You guys and your kinks...
-
@ben_lubar said in C# try/catch/finally:
If you're a function in an arbitrary program, you cannot ensure both of these happen:
- Run finally/defer/whatever your language of choice has for everything in the call stack
- Exit the process
You can either do an exit syscall or throw an exception/panic. As long as the finally block can execute code, it can jump straight back into the program's main loop.
How? I mean, in case of e.g.
Environment.Exit()
-
@kt_ said in C# try/catch/finally:
How? I mean, in case of e.g. Environment.Exit()
finally { while(true); }
Jumping out of the finally block into main() would be a little trickier in .NET (and probably involve CIL fuckery), but you can prevent the process exiting if you're running code while it exits.
-
@Maciejasjmj said in C# try/catch/finally:
@mott555 said in C# try/catch/finally:
@Weng Finally blocks always execute.
Not with a try/finally when try throws an unhandled exception.
Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up.
So it happens that someone asked related question last Friday on MSDN forum.
The part "is dependent on how your computer is set up" is actually whether legacyUnhandledExceptionPolicy is set to 1 somewhere in your app/web/machine.config
This is backward compatibility hack for code that relies on .NETv1.x behaviour of unhandled exception. If your server is new there should be no problem that the finally block must run.
-
@cheong said in C# try/catch/finally:
If your server is new there should be no problem that the finally block must run.
Provided you don't do anything evil to shoot a thread or process in the head. If you do, nothing that relies on the call stack is guaranteed to run. Just as if the CPU also does a hard error because of a firmware bug, you won't get the
finally
block run.Absolute guarantees are for weenies. :p
-
@kt_ said in C# try/catch/finally:
You obviously can crash the application from within an arbitrary place in code, just useJust checked it, it still allows finally's to run.Environment.Exit(0)
, IIRC.This is weird, the Microsoft documentation for Exit() says it shouldn't:
If Exit is called from a try or catch block, the code in any finally block does not execute.
-
@Maciejasjmj said in C# try/catch/finally:
Jumping out of the finally block into main() would be a little trickier in .NET
finally{ Program.Main(null); }
-
@Medinoc said in C# try/catch/finally:
@kt_ said in C# try/catch/finally:
You obviously can crash the application from within an arbitrary place in code, just useJust checked it, it still allows finally's to run.Environment.Exit(0)
, IIRC.This is weird, the Microsoft documentation for Exit() says it shouldn't:
If Exit is called from a try or catch block, the code in any finally block does not execute.
That makes some sense as
MicrosoftRaymond has been keep telling people that if the house is going to be teared-down immediately after you exit, you should just exit without bother to cleanup the house before you go. And finally block is usually used for cleanups.But if you have unmanaged resources that need to be explicitly freed, you now have leaked handle(s). So in .NETv2.0 they introduced SafeHandle because by C# specification (I'm reading version 5.0) Section 3.2, destructors of objects are always called on program termination.
-
@cheong said in C# try/catch/finally:
@Medinoc said in C# try/catch/finally:
@kt_ said in C# try/catch/finally:
You obviously can crash the application from within an arbitrary place in code, just useJust checked it, it still allows finally's to run.Environment.Exit(0)
, IIRC.This is weird, the Microsoft documentation for Exit() says it shouldn't:
If Exit is called from a try or catch block, the code in any finally block does not execute.
That makes some sense as
MicrosoftRaymond has been keep telling people that if the house is going to be teared-down immediately after you exit, you should just exit without bother to cleanup the house before you go. And finally block is usually used for cleanups.But if you have unmanaged resources that need to be explicitly freed, you now have leaked handle(s). So in .NETv2.0 they introduced SafeHandle because by C# specification (I'm reading version 5.0) Section 3.2, destructors of objects are always called on program termination.
What happens if you have two objects of a type with a destructor that contains an infinite loop?
-
@ben_lubar said in C# try/catch/finally:
@cheong said in C# try/catch/finally:
@Medinoc said in C# try/catch/finally:
@kt_ said in C# try/catch/finally:
You obviously can crash the application from within an arbitrary place in code, just useJust checked it, it still allows finally's to run.Environment.Exit(0)
, IIRC.This is weird, the Microsoft documentation for Exit() says it shouldn't:
If Exit is called from a try or catch block, the code in any finally block does not execute.
That makes some sense as
MicrosoftRaymond has been keep telling people that if the house is going to be teared-down immediately after you exit, you should just exit without bother to cleanup the house before you go. And finally block is usually used for cleanups.But if you have unmanaged resources that need to be explicitly freed, you now have leaked handle(s). So in .NETv2.0 they introduced SafeHandle because by C# specification (I'm reading version 5.0) Section 3.2, destructors of objects are always called on program termination.
What happens if you have two objects of a type with a destructor that contains an infinite loop?
You have to kill the process.
The contract just ensures your destructor will run but the .NET runtime on Environment.Exit(), but on the case of forced termination where the runtime itself will also be killed, of course no code will be executed.
-
@Medinoc said in C# try/catch/finally:
@kt_ said in C# try/catch/finally:
You obviously can crash the application from within an arbitrary place in code, just useJust checked it, it still allows finally's to run.Environment.Exit(0)
, IIRC.This is weird, the Microsoft documentation for Exit() says it shouldn't:
If Exit is called from a try or catch block, the code in any finally block does not execute.
Funny, I'll have to check it out again when at work.
-
There is a few way of doing this but for just a generic error page you can define it in the web.config.
Also this is a handy reference:
-
If Exit is called from a try or catch block, the code in any finally block does not execute.
but also
Exit requires the caller to have permission to call unmanaged code.
so nasal demons and all-round mayhem are already allowed to occur and they (vendor) couldn't guarantee anything even if they tried.
-
@cheong said in C# try/catch/finally:
The contract just ensures your destructor will run but the .NET runtime on Environment.Exit(), but on the case of forced termination where the runtime itself will also be killed, of course no code will be executed.
So the system makes a best effort attempt to run destructors, finalizers,
final
blocks, etc., but cannot guarantee it? Seems reasonable.
-
@lucas1 said in C# try/catch/finally:
There is a few way of doing this but for just a generic error page you can define it in the web.config.
Also this is a handy reference:
The problem is I'm forced to subvert the normal functioning of the MVC controller and have it pretend to be an API. So by default an error in your typical controller will return HTML, when the API-pretending portions really need to return API-like errors.
This is what I get for going along with my predecessor's work that is .
I do appreciate the help though, even if it's unlikely I will be able to come up with a satisfactory solution.
-
@Tsaukpaetra In the Global.asax file, you can change the application_error handler.