Exception/Error division in D

Jonathan M Davis jmdavisProg at gmx.com
Wed May 30 14:36:50 PDT 2012


On Wednesday, May 30, 2012 17:29:30 Don Clugston wrote:
> On 30/05/12 12:59, Jonathan M Davis wrote:
> > On Wednesday, May 30, 2012 11:32:00 Don Clugston wrote:
> >> On 30/05/12 10:40, Jonathan M Davis wrote:
> >>> On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:
> >>>> The fact that error don't trigger scope and everything is nonsensial.
> >>> 
> >>> If an Error is truly unrecoverable (as they're generally supposed to
> >>> be),
> >>> then what does it matter? Something fatal occured in your program, so it
> >>> terminates. Because it's an Error, you can get a stack trace and report
> >>> something before the program actually terminates, but continuing
> >>> execution after an Error is considered to be truly _bad_ idea, so in
> >>> general, why does it matter whether scope statements, finally blocks, or
> >>> destructors get executed? It's only rarer cases where you're trying to
> >>> do
> >>> something like create a unit test framework on top of assert that you
> >>> would need to catch an Error, and that's questionable enough as it is.
> >>> In
> >>> normal program execution, an error is fatal, so cleanup is irrelevant
> >>> and
> >>> even potentially dangerous, because your program is already in an
> >>> invalid
> >>> state.
> >> 
> >> That's true for things like segfaults, but in the case of an
> >> AssertError, there's no reason to believe that cleanup would cause any
> >> damage.
> >> In fact, generally, the point of an AssertError is to prevent the
> >> program from entering an invalid state.
> > 
> > An assertion failure really isn't all that different from a segfault. By
> > definition, if an assertion fails, the program is an invalid state,
> > because the whole point of the assertion is to guarantee something about
> > the program's state.
> 
> There's a big difference. A segfault is a machine error. The integrity
> of the machine model has been violated, and the machine is in an
> out-of-control state. In particular, the stack may be corrupted, so
> stack unwinding may not be successful.
> 
> But, in an assert error, the machine is completely intact; the error is
> at a higher level, which does not interfere with stack unwinding.
> 
> Damage is possible only if you've written your destructors/finally code
> extremely poorly. Note that, unlike C++, it's OK to throw a new Error or
> Exception from inside a destructor.
> But with (say) a stack overflow, you don't necessarily know what code is
> being executed. It could do anything.

There is definitely a difference in severity. Clearly memory corruption is more 
severe than a logic error in your code. However, in the general case, if you 
have a logic error in your code which is caught by an assertion, there's no 
way to know without actually examining the code how valid the state of the 
program is at that point. It's in an invalid state _by definition_, because the 
assertion was testing the validity of the state of the program, and it failed. 
So, at that point, it's only a question of degree. _How_ invalid is the state? 
Since there's no way for the program to know how severe the logic error was, 
it has no way of knowing whether it's safe to run any cleanup code (the same 
as the program has no way of knowing whether a segfault is relatively minor - 
e.g. a null pointer - or absolutely catastrophic - e.g. memory is horribly 
corrupted).

If you got an OutOfMemoryError rather than one specifically indicating a logic 
error (as with Errors such as AssertError or RangeError), then that's 
specifcally telling you that your program has run out of a particular resource 
(i.e. memory), which means that any code which assumes that that resource is 
available (which in the case of memory is pretty much all code) will fail. 
Running cleanup code could be very precarious at that point if it allocates 
any memory (which a lot of cleanup code wouldn't, but I'm sure that it would 
be very easy to find cleanup code which did). Any further attempts at 
allocation would result in more OutOfMemoryErrors and leaving the cleanup code 
only partially run, thereby possibly making things even worse, depending on 
what the cleanup code does.

Running cleanup code is _not_ safe when an Error is thrown, because the 
program is definitely in an invalid state at that point, even if it's not as 
bad as a segfault can be.

Now, it may be that that risk is worth it, especially since a lot of the time, 
cleanup code won't be invalidated in the least by whatever caused Errors 
elsewhere in the program, and there are definitely plenty of cases where at 
least attempting to cleanup everything is better than skipping it all due of 
an Error somewhere else in the program. But it's still not safe. It's a 
question of whether we think that the risks posed by trying to run cleanup 
code after the program is in an invalid enough state that an Error was thrown 
are too great to attempt cleanup or whether we think that the problems caused 
by skipping that cleanup are greater.

> > Now, if a segfault occurs (particularly if it's caused by something
> > other than a null pointer), the program is likely to be in a _worse_
> > state,
> > but it's in an invalid state in either case. In neither case does it make
> > any sense to try and recover, and in both cases, there's a definite risk
> > in executing any further code - including cleanup code.
> > 
> > Yes, the segfault is
> > probably worse but not necessarily all that much worse. A logic error can
> > be just as insidious to the state of a program as memory corruption,
> > depending on what it is.
> 
> I'm surprised by your response, I didn't think this was controversial.
> We could just as easily have said assert() throws an AssertException.
> (Or have two kinds of assert, one which is an Error and the other merely
> an Exception).

In general, a segfault is definitely worse, but logic errors can_ be just as 
bad in terms of the damage that they can do (especially in cmparison with 
segfaults caused by null pointers as opposed to those caused by memory 
corruption). It all depends on what the logic error is and what happens if you 
try and continue with the program in such a state.

- Jonathan M Davis


More information about the Digitalmars-d mailing list