Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
259 views
in Technique[技术] by (71.8m points)

c++ - What happens if 'throw' fails to allocate memory for exception object?

From C++11 standard (15.1.p4):

The memory for the exception object is allocated in an unspecified way, except as noted in 3.7.4.1

What if allocation fails -- will it throw std::bad_alloc instead? Call std::terminate? Unspecified?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

(providing my own answer... I'll wait for few days and if there are no problems with it -- I'll mark it as accepted)

I spent some time investigating this and here is what I unearthed:

  • C++ standard does not specify what is going to happen in this case
  • Clang and GCC seem to use C++ Itanium ABI

Itanimum ABI suggests to use heap for exceptions:

Storage is needed for exceptions being thrown. This storage must persist while stack is being unwound, since it will be used by the handler, and must be thread-safe. Exception object storage will therefore normally be allocated in the heap

...

Memory will be allocated by the __cxa_allocate_exception runtime library routine.

So, yeah... throwing an exception will likely involve locking mutexes and searching for a free memory block. :-(

It also mentions this:

If __cxa_allocate_exception cannot allocate an exception object under these constraints, it calls terminate()

Yep... in GCC and Clang "throw myX();" can kill your app and you can't do a thing about it (maybe writing your own __cxa_allocate_exception can help -- but it certainly won't be portable)

It gets even better:

3.4.1 Allocating the Exception Object

Memory for an exception object will be allocated by the __cxa_allocate_exception runtime library routine, with general requirements as described in Section 2.4.2. If normal allocation fails, then it will attempt to allocate one of the emergency buffers, described in Section 3.3.1, under the following constraints:

  • The exception object size, including headers, is under 1KB.
  • The current thread does not already hold four buffers.
  • There are fewer than 16 other threads holding buffers, or this thread will wait until one of the others releases its buffers before acquiring one.

Yep, your program can simply hang! Granted chance of this are small -- you'd need to exhaust memory and your threads need to use up all 16 emergency buffers and enter wait for another thread that should generate an exception. But if you do things with std::current_exception (like chaining exception and passing them between threads) -- it is not so improbable.

Conclusion:

This is a deficiency in C++ standard -- you can't write 100% reliable programs (that use exceptions). Text book example is a server that accepts connections from clients and executes submitted tasks. Obvious approach to handle problems would be to throw an exception, which will unwind everything and close connection -- all other clients won't be affected and server will continue to operate (even under low memory conditions). Alas, such server is impossible to write in C++.

You can claim that modern systems (i.e. Linux) will kill such server before we reach this situation anyway. But (1) it is not an argument; (2) memory manager can be set to overcommit; (3) OOM killer won't be triggered for 32-bit app running on 64bit hardware with enough memory (or if app artificially limited memory allocation).

On personal note I am quite pissed about this discovery -- for many years I claimed that my code handles out-of-memory gracefully. Turns out I lied to my clients. :-( Might as well start intercepting memory allocation, call std::terminate and treat all related functions as noexcept -- this will certainly make my life easier (coding-wise). No wonder they still use Ada to programs rockets.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...