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

后端 未结 4 429
走了就别回头了
走了就别回头了 2020-11-30 01:48

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

4条回答
  •  感动是毒
    2020-11-30 02:15

    Current answer already describes what GCC does. I have checked MSVC behavior - it allocates exception on the stack, so allocation does not depend on the heap. This makes stack overflow is possible (exception object can be big), but stack overflow handling is not covered by standard C++.

    I used this short program to examine what happens during exception throw:

    #include 
    
    class A {
    public:
        A() { std::cout << "A::A() at " << static_cast(this) << std::endl; }
        A(const A &) { std::cout << "A::A(const A &) at " << static_cast(this) << std::endl; }
        A(A &&) { std::cout << "A::A(A &&) at " << static_cast(this) << std::endl; }
        ~A() { std::cout << "A::~A() at " << static_cast(this) << std::endl; }
        A &operator=(const A &) = delete;
        A &operator=(A &&) = delete;
    };
    
    int main()
    {
        try {
            try {
                try {
                    A a;
                    throw a;
                } catch (const A &ex) {
                    throw;
                }
            } catch (const A &ex) {
                throw;
            }
        } catch (const A &ex) {
        }
    }
    

    When build with GCC output clearly shows that exception thrown is being allocated far from stack:

    A::A() at 0x22cad7
    A::A(A &&) at 0x600020510
    A::~A() at 0x22cad7
    A::~A() at 0x600020510
    

    When build with MSVC output shows that exception is allocated nearby on the stack:

    A::A() at 000000000018F4E4
    A::A(A &&) at 000000000018F624
    A::~A() at 000000000018F4E4
    A::~A() at 000000000018F624
    

    Additional examination with debugger shows that catch handlers and destructors are executed on the top of the stack, so stack consumption grows with each catch block starting with the first throw and until std::uncaught_exceptions() becomes 0.

    Such behavior means that correct out of memory handling requires you to prove there is enough stack space for the program to execute exception handlers and all destructors on the way.

    To prove the same with GCC it seems that you will need to prove there no more than four nested exceptions and exceptions have size less than 1KiB (this includes header). Additionally if some thread has more than four nested exceptions, you also need to prove there is no deadlock caused by emergency buffer allocation.

提交回复
热议问题