www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - nogc and exceptions

reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
There is one massive blocker for ` nogc` adoption in D library 
code: allocation of exception objects. The GC heap is an ideal 
location for exception objects, but ` nogc` has to stick to its 
promise, so an alternative method of memory management is 
desirable if we want the standard library to be widely usable in 
` nogc` user code, as well as enabling third-party libraries to 
apply ` nogc`. If we don't solve this, we'll stratify D code into 
two separate camps, the GC-using camp and the ` nogc`-using camp, 
each with their own set of library code.

I can think of a couple of ways to go:

1) The most widely discussed path is to allocate exception 
instances statically, either in global memory or TLS. Currently, 
this has a few serious problems:

   1a) If the exception is chained, that is, if the same exception 
appears twice in the same exception chain - which can easily 
happen when an exception is thrown from a `scope(exit|failure)` 
statement or from a destructor - the chaining mechanism will 
construct a self-referencing list that results in an infinite 
loop when the chain is walked, such as by the global exception 
handler that prints the chain to stderr. This can easily be 
demonstrated with the below snippet:

---
void main()
{
     static immutable ex = new Exception("");
     scope(exit) throw ex;
     throw ex;
}
---

Amending the chaining mechanism to simply *disallow* these chains 
would neuter exception chaining severely, in fact making it more 
or less useless: it's not realistically possible to predict which 
exceptions will appear twice when calling code from multiple 
libraries.

   1b) Exceptions constructed at compile-time which are then later 
referenced at runtime (as in the above snippet) must be immutable 
(the compiler enforces this), as this feature only supports 
allocation in global memory, not in TLS. This brings us to an 
unsolved bug in the exception mechanism - the ability to get a 
mutable reference to an immutable exception without using a cast:

---
void main()
{
     static immutable ex = new Exception("");
     try throw ex;
     catch(Exception e) // `e` is a mutable reference
     {
         // The exception is caught and `e` aliases `ex`
     }
}
---

Fixing this would likely involve requiring 
`catch(const(Exception) e)` at the catch-site, which would 
require users to update all their exception-handling code, and if 
they don't, the program will happily compile but the catch-site 
no longer matches. This is especially egregious as error-handling 
code is often the least tested part of the program. Essentially 
D's entire exception mechanism is not const-correct.

   1c) Enhancing the compiler to allow statically constructing in 
TLS, or allocating space in TLS first then constructing the 
exception lazily at runtime, would allow us to keep throwing 
mutable exceptions, but would seriously bloat the TLS section. We 
can of course allocate shared instances in global memory and 
throw those, but this requires thread-safe code at the catch-site 
which has similar problems to catching by const.

2) The above really shows how beneficial dynamic memory 
allocation is for exceptions. A possibility would be to allocate 
exceptions on a non-GC heap, like the C heap (malloc) or a 
thread-local heap. Of course, without further amendments the onus 
is then on the catch-site to explicitly manage memory, which 
would silently break virtually all exception-handling code really 
badly.

However, if we assume that most catch-sites *don't* escape 
references to exceptions from the caught chain, we could 
gracefully work around this with minimal and benevolent breakage: 
amend the compiler to implicitly insert a cleanup call at the end 
of each catch-block. The cleanup function would destroy and free 
the whole chain, but only if a flag indicates that the exception 
was allocated with this standard heap mechanism. Chains of 
exceptions with mixed allocation origin would have to be dealt 
with in some manner. If inside the catch-block, the chain is 
rethrown or sent in flight by a further exception, the cleanup 
call would simply not be reached and deferred to the next 
catch-site, and so on.

Escaping references to caught exceptions would be undefined 
behaviour. To statically enforce this doesn't happen, exception 
references declared in catch-blocks could be made implicitly 
`scope`. This depends on `scope` actually working reasonably 
well. This would be the only breaking change for user code, and 
the fix is simply making a copy of the escaped exception.

Anyway, I'm wondering what thoughts you guys have on this nascent 
but vitally important issue. What do we do about this?
Sep 11 2014
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Friday, 12 September 2014 at 03:37:10 UTC, Jakob Ovrum wrote:
 2) The above really shows how beneficial dynamic memory 
 allocation is for exceptions. A possibility would be to 
 allocate exceptions on a non-GC heap, like the C heap (malloc) 
 or a thread-local heap. Of course, without further amendments 
 the onus is then on the catch-site to explicitly manage memory, 
 which would silently break virtually all exception-handling 
 code really badly.

 However, if we assume that most catch-sites *don't* escape 
 references to exceptions from the caught chain, we could 
 gracefully work around this with minimal and benevolent 
 breakage: amend the compiler to implicitly insert a cleanup 
 call at the end of each catch-block. The cleanup function would 
 destroy and free the whole chain, but only if a flag indicates 
 that the exception was allocated with this standard heap 
 mechanism. Chains of exceptions with mixed allocation origin 
 would have to be dealt with in some manner. If inside the 
 catch-block, the chain is rethrown or sent in flight by a 
 further exception, the cleanup call would simply not be reached 
 and deferred to the next catch-site, and so on.

 Escaping references to caught exceptions would be undefined 
 behaviour. To statically enforce this doesn't happen, exception 
 references declared in catch-blocks could be made implicitly 
 `scope`. This depends on `scope` actually working reasonably 
 well. This would be the only breaking change for user code, and 
 the fix is simply making a copy of the escaped exception.

 Anyway, I'm wondering what thoughts you guys have on this 
 nascent but vitally important issue. What do we do about this?
I think option "b)" is the right direction. However, I don't think it is reasonable to have the "catch" code be responsible for the cleanup proper, as that would lead to a closed design (limited allocation possibilities). I like the option of having "exception allocators" that can later be explicitly called in a "release all exceptions" style, or plugged into the GC, to be cleaned up automatically like any other GC allocated exception. This would make the exceptions themselves still nogc, but the GC would have a hook to (potentially) collect them. For those that don't want that, then they can make calls to the cleanup at deterministic times. This, combined with the fact that we used an (unshared) allocator means the cleanup itself would be 0(1). Finally, if somebody *does* want to keep exceptions around, he would still be free to do so *provided* he re-allocates the exceptions himself using a memory scheme he chooses to use (a simple GC new, for example). ... well, either that, or have each exception carry a callback to its allocator, so that catch can do the cleanup, regardless of who did the allocation, and how. GC exceptions would have no callback, meaning a "catch" would still be nogc. An existing code that escapes exceptions would not immediately break. Either way, some sort of custom (no-gc) allocator seems in order here.
Sep 12 2014
next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
12-Sep-2014 15:03, monarch_dodra пишет:
 I like the option of having "exception allocators" that can later be
 explicitly called in a "release all exceptions" style, or plugged into
 the GC, to be cleaned up automatically like any other GC allocated
 exception. This would make the exceptions themselves still  nogc, but
 the GC would have a hook to (potentially) collect them. For those that
 don't want that, then they can make calls to the cleanup at
 deterministic times.

 This, combined with the fact that we used an (unshared) allocator means
 the cleanup itself would be 0(1).

 Finally, if somebody *does* want to keep exceptions around, he would
 still be free to do so *provided* he re-allocates the exceptions himself
 using a memory scheme he chooses to use (a simple GC new, for example).



 ... well, either that, or have each exception carry a callback to its
 allocator, so that catch can do the cleanup, regardless of who did the
 allocation, and how. GC exceptions would have no callback, meaning a
 "catch" would still be  nogc. An existing code that escapes exceptions
 would not immediately break.

 Either way, some sort of custom (no-gc) allocator seems in order here.
Agreed. I think that the total amount of live (not garbage) exceptions on heap is small for any typical application. Thus just special casing the hell out of exception allocation in the GC (and compiler) is IMO perfectly satisfactory hack. -- Dmitry Olshansky
Sep 12 2014
parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Friday, 12 September 2014 at 16:33:50 UTC, Dmitry Olshansky 
wrote:
 Agreed.

 I think that the total amount of live (not garbage) exceptions 
 on heap is small for any typical application. Thus just special 
 casing the hell out of exception allocation in the GC (and 
 compiler) is IMO perfectly satisfactory hack.
We can't use the GC as the whole point is to mark library code ` nogc`. It should work even if the user has ripped the GC out of druntime with a custom build.
Sep 12 2014
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
13-Sep-2014 06:01, Jakob Ovrum пишет:
 On Friday, 12 September 2014 at 16:33:50 UTC, Dmitry Olshansky wrote:
 Agreed.

 I think that the total amount of live (not garbage) exceptions on heap
 is small for any typical application. Thus just special casing the
 hell out of exception allocation in the GC (and compiler) is IMO
 perfectly satisfactory hack.
We can't use the GC as the whole point is to mark library code ` nogc`. It should work even if the user has ripped the GC out of druntime with a custom build.
Then call it "exception heap" or some such, and make sure it's somehow separate. It still means GC got to scan it. -- Dmitry Olshansky
Sep 13 2014
prev sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Friday, 12 September 2014 at 11:03:09 UTC, monarch_dodra wrote:
 I think option "b)" is the right direction. However, I don't 
 think it is reasonable to have the "catch" code be responsible 
 for the cleanup proper, as that would lead to a closed design 
 (limited allocation possibilities).
Exceptions using other alocators simply don't set the flag.
 I like the option of having "exception allocators" that can 
 later be explicitly called in a "release all exceptions" style, 
 or plugged into the GC, to be cleaned up automatically like any 
 other GC allocated exception. This would make the exceptions 
 themselves still  nogc, but the GC would have a hook to 
 (potentially) collect them. For those that don't want that, 
 then they can make calls to the cleanup at deterministic times.
We can't change existing instances of `throw` to use such a manually managed heap without silently causing user code to leak.
 Finally, if somebody *does* want to keep exceptions around, he 
 would still be free to do so *provided* he re-allocates the 
 exceptions himself using a memory scheme he chooses to use (a 
 simple GC new, for example).
Yes, but we can't let existing code that escapes exceptions run into memory corruption because we changed the allocator. We need `scope`.
 ... well, either that, or have each exception carry a callback 
 to its allocator, so that catch can do the cleanup, regardless 
 of who did the allocation, and how. GC exceptions would have no 
 callback, meaning a "catch" would still be  nogc. An existing 
 code that escapes exceptions would not immediately break.
I think this would depend on having multiple proposed exception allocation strategies in the first place. We know when the cleanup happens and we roughly know the allocation pattern (exceptional paths are rarely hit etc.), so I think we should focus on finding/creating an allocator ideal for this pattern, then apply it to Phobos.
Sep 12 2014
prev sibling next sibling parent reply Andrej Mitrovic via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 9/12/14, Jakob Ovrum via Digitalmars-d <digitalmars-d puremagic.com> wrote:
 the chaining mechanism will
 construct a self-referencing list that results in an infinite
 loop when the chain is walked
Can we amend the spec to say self-referencing is ok? Then we could make the default exception handler *stop* if it finds a self-referencing exception (e.g. for stack traces), and for custom user code which walks through exceptions it would either have to be fixed. We could also provide a helper function for walking through exceptions: try { ... } catch (Exception ex) { // some UFCS or object.d built-in method which // stops walking when ".next is this" foreach (caught; ex.walk) { } } Or does the problem have a bigger scope than just walking?
Sep 12 2014
parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Friday, 12 September 2014 at 11:38:18 UTC, Andrej Mitrovic via 
Digitalmars-d wrote:
 On 9/12/14, Jakob Ovrum via Digitalmars-d 
 <digitalmars-d puremagic.com> wrote:
 the chaining mechanism will
 construct a self-referencing list that results in an infinite
 loop when the chain is walked
Can we amend the spec to say self-referencing is ok? Then we could make the default exception handler *stop* if it finds a self-referencing exception (e.g. for stack traces), and for custom user code which walks through exceptions it would either have to be fixed. We could also provide a helper function for walking through exceptions: try { ... } catch (Exception ex) { // some UFCS or object.d built-in method which // stops walking when ".next is this" foreach (caught; ex.walk) { } } Or does the problem have a bigger scope than just walking?
The exception chain would be unable to chain further exceptions. Each exception in the chain needs its own unique `next` pointer. Also, the two links to the same exception could appear anywhere in the list. I think some sort of caching of exceptions already encountered would be required, which is a lot slower and more complex than the existing mechanism.
Sep 12 2014
prev sibling next sibling parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Friday, 12 September 2014 at 03:37:10 UTC, Jakob Ovrum wrote:
 I can think of a couple of ways to go:
 1) The most widely discussed path is to allocate exception 
 instances statically, either in global memory or TLS. 
 Currently, this has a few serious problems:
Another problem with this is that you'll need to change every instance of "new FooException" to something else. Here's a crazy idea that will never fly: 1. Opt-in reference counting for classes. This needs language/compiler support because currently we can't have both reference counting and inheritance. For example, you could annotate Throwable as refcounted, and all descendants get it automatically. The ref-counting overhead of exceptions should be acceptable (even with locks), since exceptions should be exceptional. 2. Bring back the currently-deprecated new/delete operator overloading. If we could have reference-counted classes that are allocated on the C heap, and keep the "new FooException" syntax, the problem could be solved globally and transparently. Reference counting implies that copies done using memcpy/unions/etc. will not be tracked, but nobody does that with exception objects, right?
Sep 12 2014
next sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Fri, 12 Sep 2014 12:47:44 +0000
schrieb "Vladimir Panteleev" <vladimir thecybershadow.net>:

 On Friday, 12 September 2014 at 03:37:10 UTC, Jakob Ovrum wrote:
 I can think of a couple of ways to go:
 1) The most widely discussed path is to allocate exception 
 instances statically, either in global memory or TLS. 
 Currently, this has a few serious problems:
Another problem with this is that you'll need to change every instance of "new FooException" to something else. Here's a crazy idea that will never fly: 1. Opt-in reference counting for classes. This needs language/compiler support because currently we can't have both reference counting and inheritance. For example, you could annotate Throwable as refcounted, and all descendants get it automatically. The ref-counting overhead of exceptions should be acceptable (even with locks), since exceptions should be exceptional. 2. Bring back the currently-deprecated new/delete operator overloading. If we could have reference-counted classes that are allocated on the C heap, and keep the "new FooException" syntax, the problem could be solved globally and transparently. Reference counting implies that copies done using memcpy/unions/etc. will not be tracked, but nobody does that with exception objects, right?
I think if we could avoid dynamic allocations for most exceptions completely that'd be better. IIRC some people said that exceptions are mainly slow because of memory allocation. So if we could avoid that, there are more benefits. I suggest looking at the C++ implementation. There's the throw-by-value catch-by-reference idiom. C++ must store/copy this exception somewhere, maybe they have a clever solution. (We basically need some fixed-size per thread memory where we can store the exception and stack trace info. But we need a fallback because of exception chaining or big exceptions.)
Sep 12 2014
next sibling parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Friday, 12 September 2014 at 21:36:31 UTC, Johannes Pfau wrote:
 I suggest looking at the C++ implementation. There's the 
 throw-by-value
 catch-by-reference idiom. C++ must store/copy this exception 
 somewhere,
 maybe they have a clever solution.
But then we can't have exception stack traces.
Sep 12 2014
prev sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Friday, 12 September 2014 at 21:36:31 UTC, Johannes Pfau wrote:
 I think if we could avoid dynamic allocations for most 
 exceptions
 completely that'd be better. IIRC some people said that 
 exceptions are
 mainly slow because of memory allocation. So if we could avoid 
 that,
 there are more benefits.
While we should ideally make the exception mechanism as fast as possible, it mustn't be a priority, lest we compromise more important parts of the design for the red herring that is performance. If a program is slow because of exception handling it's not using exceptions correctly. It should replace that part of the code with a solution that uses error codes. This is the mantra that goes for all languages with exceptions that I know, except Python and maybe Java. Also, we know the approximate size of exceptions and their allocation pattern. An efficient heap allocator could be designed to take advantage of this. That's not to say I'm against any non-heap solution if we can think of something really good, but we should keep our priorities straight.
 I suggest looking at the C++ implementation. There's the 
 throw-by-value
 catch-by-reference idiom. C++ must store/copy this exception 
 somewhere,
 maybe they have a clever solution.

 (We basically need some fixed-size per thread memory where we 
 can store
 the exception and stack trace info. But we need a fallback 
 because of
 exception chaining or big exceptions.)
I think this is essentially global storage allocation. C++ does not do exception chaining so this is much more viable there. Also, when we decide to use TLS instead of the mess that would be shared exceptions, we introduce a massive chunk of required data for each new thread in every application that depends on Phobos and/or other libraries using the new exception allocator.
Sep 12 2014
prev sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Friday, 12 September 2014 at 12:47:46 UTC, Vladimir Panteleev
wrote:
 On Friday, 12 September 2014 at 03:37:10 UTC, Jakob Ovrum wrote:
 I can think of a couple of ways to go:
 1) The most widely discussed path is to allocate exception 
 instances statically, either in global memory or TLS. 
 Currently, this has a few serious problems:
Another problem with this is that you'll need to change every instance of "new FooException" to something else.
I don't think this is a big problem, ` nogc` will tell you where the allocations are, and it's fairly easy to just grep and replace. It's also worth noting that code using enforce et al. could be updated automatically. Further, you only need to do this if you want your library code to be ` nogc`. Existing code using the GC-heap will keep working (except for the `scope` thing I proposed...).
Sep 12 2014
prev sibling next sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 12 September 2014 at 03:37:10 UTC, Jakob Ovrum wrote:
   1b) Exceptions constructed at compile-time which are then 
 later referenced at runtime (as in the above snippet) must be 
 immutable (the compiler enforces this), as this feature only 
 supports allocation in global memory, not in TLS. This brings 
 us to an unsolved bug in the exception mechanism - the ability 
 to get a mutable reference to an immutable exception without 
 using a cast:
Related: Last time I checked the runtime caches unwinding or stack trace information in the exception. It does this even for immutable exceptions...
 Escaping references to caught exceptions would be undefined 
 behaviour. To statically enforce this doesn't happen, exception 
 references declared in catch-blocks could be made implicitly 
 `scope`. This depends on `scope` actually working reasonably 
 well. This would be the only breaking change for user code, and 
 the fix is simply making a copy of the escaped exception.
Care must also be taken when the exception is forwarded to another thread, like `receive()` does. `scope` forcing to copy the exception would solve a part of that, but to be completely correct, the exception would either have to shared, or a deep copy would be necessary.
Sep 12 2014
parent reply Johannes Pfau <nospam example.com> writes:
Am Fri, 12 Sep 2014 12:59:22 +0000
schrieb "Marc Sch=C3=BCtz" <schuetzm gmx.net>:

 On Friday, 12 September 2014 at 03:37:10 UTC, Jakob Ovrum wrote:
   1b) Exceptions constructed at compile-time which are then=20
 later referenced at runtime (as in the above snippet) must be=20
 immutable (the compiler enforces this), as this feature only=20
 supports allocation in global memory, not in TLS. This brings=20
 us to an unsolved bug in the exception mechanism - the ability=20
 to get a mutable reference to an immutable exception without=20
 using a cast:
=20 Related: Last time I checked the runtime caches unwinding or=20 stack trace information in the exception. It does this even for=20 immutable exceptions...
Yes, in order to avoid allocating a stack trace helper you need to cast the exception from its .init property, IIRC. There's some code in druntime which does that (the out-of-memory error handling code).
Sep 12 2014
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 12 September 2014 at 21:31:45 UTC, Johannes Pfau wrote:
 Am Fri, 12 Sep 2014 12:59:22 +0000
 schrieb "Marc Schütz" <schuetzm gmx.net>:

 On Friday, 12 September 2014 at 03:37:10 UTC, Jakob Ovrum 
 wrote:
   1b) Exceptions constructed at compile-time which are then 
 later referenced at runtime (as in the above snippet) must 
 be immutable (the compiler enforces this), as this feature 
 only supports allocation in global memory, not in TLS. This 
 brings us to an unsolved bug in the exception mechanism - 
 the ability to get a mutable reference to an immutable 
 exception without using a cast:
Related: Last time I checked the runtime caches unwinding or stack trace information in the exception. It does this even for immutable exceptions...
Yes, in order to avoid allocating a stack trace helper you need to cast the exception from its .init property, IIRC. There's some code in druntime which does that (the out-of-memory error handling code).
That's not what I mean, please see here: http://forum.dlang.org/thread/ftakrucgtfcicfbkzwbs forum.dlang.org#post-xmvzmufjywcsxviooivl:40forum.dlang.org
Sep 13 2014
parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Saturday, 13 September 2014 at 08:19:10 UTC, Marc Schütz wrote:
 On Friday, 12 September 2014 at 21:31:45 UTC, Johannes Pfau 
 wrote:
 Am Fri, 12 Sep 2014 12:59:22 +0000
 schrieb "Marc Schütz" <schuetzm gmx.net>:
 Related: Last time I checked the runtime caches unwinding or 
 stack trace information in the exception. It does this even 
 for immutable exceptions...
Yes, in order to avoid allocating a stack trace helper you need to cast the exception from its .init property, IIRC. There's some code in druntime which does that (the out-of-memory error handling code).
That's not what I mean, please see here: http://forum.dlang.org/thread/ftakrucgtfcicfbkzwbs forum.dlang.org#post-xmvzmufjywcsxviooivl:40forum.dlang.org
Indeed the entire exception mechanism does not account for immutability at all which is not surprising considering it was implemented in the days of D1 and there's a lot of type erasure going on when druntime functions are called, but it does mean any sighting of a non-mutable exception anywhere is a big red flag until we overhaul exceptions to account for immutability.
Sep 13 2014
prev sibling parent reply "Dicebot" <public dicebot.lv> writes:
I am obviously in favor of simply calling recurrent mutable 
exception chains illegal (probably even immutable ones until we 
fix const correctness of druntime exception handling).

Reason is simple : it doesn't require any changes in existing 
code and is exactly the way we already do it in Sociomantic :)

To make it reliable Exception chain may need to be updated to 
doubly-linked list to be able to efficiently verify that new 
exception is not already present in the chain. I don't see any 
costly overhead implications from that though.
Sep 19 2014
parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Friday, 19 September 2014 at 07:57:24 UTC, Dicebot wrote:
 I am obviously in favor of simply calling recurrent mutable 
 exception chains illegal (probably even immutable ones until we 
 fix const correctness of druntime exception handling).

 Reason is simple : it doesn't require any changes in existing 
 code and is exactly the way we already do it in Sociomantic :)

 To make it reliable Exception chain may need to be updated to 
 doubly-linked list to be able to efficiently verify that new 
 exception is not already present in the chain. I don't see any 
 costly overhead implications from that though.
That might be sufficient for a particular application like Sociomantic's, but it's not sufficient for library code in general. Such chains aren't logic errors and can easily occur in the wild. The point of exception chaining is so exceptions can be thrown in destructors and such. In library code, these destructors don't know what exception is in flight, so they can only assume it could be any exception. If self-referencing chains were illegal and exceptions were statically allocated, then the conclusion is that these destructors can't throw anything after all, because that exception might already be in flight. As such, exception chaining would be completely useless.
Sep 19 2014
parent "Dicebot" <public dicebot.lv> writes:
On Friday, 19 September 2014 at 11:36:29 UTC, Jakob Ovrum wrote:
 That might be sufficient for a particular application like 
 Sociomantic's, but it's not sufficient for library code in 
 general. Such chains aren't logic errors and can easily occur 
 in the wild.

 The point of exception chaining is so exceptions can be thrown 
 in destructors and such. In library code, these destructors 
 don't know what exception is in flight, so they can only assume 
 it could be any exception. If self-referencing chains were 
 illegal and exceptions were statically allocated, then the 
 conclusion is that these destructors can't throw anything after 
 all, because that exception might already be in flight. As 
 such, exception chaining would be completely useless.
This is pretty much saying that anything should be able to throw anything. For me it sounds as flawed application - if recurrent chaining happens when handling destructor, most likely there is a fundamental programming error in application logic (some sort of cyclic dependency) and it should be pointed to and fixed. Probably there is some convincing example of such legal code but I can't imagine it on my own.
Sep 19 2014