Bug 24025 - libstdc++ crashes when out of memory exception thrown
Summary: libstdc++ crashes when out of memory exception thrown
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.0.0
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-09-22 22:00 UTC by Geoff Keating
Modified: 2016-01-17 23:53 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2006-03-01 02:20:01


Attachments
Trivial testcase (260 bytes, text/plain)
2005-12-02 17:40 UTC, Paolo Carlini
Details
Puzzling testcase... (283 bytes, text/plain)
2005-12-02 18:02 UTC, Paolo Carlini
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Geoff Keating 2005-09-22 22:00:36 UTC
In __cxa_get_globals, the code does:

      if ((g = (__cxa_eh_globals *)
           std::malloc (sizeof (__cxa_eh_globals))) == 0
          || __gthread_setspecific (globals_key, (void *) g) != 0)
        std::terminate ();

but since __cxa_get_globals is called in __cxa_allocate_exception, the effect of this is that if the first 
exception thrown in a program is an out-of-memory exception, the program will instead call 
std::terminate, because it won't be able to allocate a new __cxa_eh_globals.  std::terminate itself 
expects __cxa_get_globals to work, so it'll call itself recursively, leading to an abort() in 
__verbose_terminate_handler.
Comment 1 Andrew Pinski 2005-09-22 23:04:25 UTC
Confirmed.
Comment 2 Paolo Carlini 2005-09-23 09:45:15 UTC
Adding Rth in CC as the author of the fix of libstdc++/10606, which added the
call of __cxa_get_globals from __cxa_allocate_exception
Comment 3 Paolo Carlini 2005-12-02 17:40:41 UTC
Created attachment 10391 [details]
Trivial testcase

Hi. I'm attaching a trivial testcase (*). In fact, I consider this bug pretty serious! Howard, any chance you can show your patch to Geoff or post it to the mailing list(s) for a review?

(*) Of course, it reliably fails stand-alone, without the def-out bits, only on 32-bit machines equipped with less than ~ 1G.
Comment 4 Paolo Carlini 2005-12-02 17:50:30 UTC
Sorry. Actually the testcase is not correct stand-alone, fails at line 13. I'm currently checking whether is correct when the testsuite support (memory limits) is present.
Comment 5 Paolo Carlini 2005-12-02 17:51:41 UTC
... possibly using a "real" memory allocation, touching all the involved pages.
Comment 6 Paolo Carlini 2005-12-02 18:02:04 UTC
Created attachment 10392 [details]
Puzzling testcase...

Humm, strange. The new testcase *passes*... Still, the original analysis makes a lot of sense to me (like Howard's suggestion for a fix). But we badly need a testcase! Any idea?
Comment 7 Paolo Carlini 2005-12-02 18:07:58 UTC
Ah! Now I see, it's because of Benjamin and Ulrich recent changes, involving thread local storage. Therefore my amended testcase proposal should be fine on platforms not defining _GLIBCXX_HAVE_TLS. We should check that.
Comment 8 Paolo Carlini 2005-12-02 18:13:14 UTC
If my analysis is correct, this PR is still valid *only* for targets not defining _GLIBCXX_HAVE_TLS. Otherwise, fixed by:

2005-11-21  Benjamin Kosnik  <bkoz@redhat.com>
            Ulrich Drepper  <drepper@redhat.com>

	PR libstdc++/23591
Comment 9 Paolo Carlini 2006-10-23 16:26:31 UTC
The issue seems more tricky, even for TLS platforms, see:

  http://gcc.gnu.org/ml/gcc-patches/2006-10/msg00333.html
Comment 10 xiaoyuanbo 2012-02-22 12:52:15 UTC
i know you are
Comment 11 Jonathan Larmour 2012-11-05 18:21:18 UTC
I'm quite surprised to find that this problem still exists in the current trunk for platforms without TLS (i.e. many embedded platforms). Although I don't see a recursive call but a rather more direct chain of events:

1) We completely run out of heap memory calling operator new. To see this problem, less than the size of 'struct __cxa_eh_globals' must be available.

2) new throws std::bad_alloc, causing __cxa_allocate_exception to be called

3) __cxa_allocate_exception calls malloc() which still fails, but an emergency buffer is available, so it is able to continue.

4) But __cxa_allocate_exception then calls __cxa_get_globals()

5) If __cxa_get_globals() has not been called before, it will allocate the globals structure beginning with a call to malloc()

6) malloc() still fails, so std::terminate() is called.

The effect is that if std::bad_alloc is the first C++ exception this thread has thrown, we can never catch it - instead the program is always abruptly terminated, by default with abort(). This seems to be a surprisingly serious issue given this is a 7 year old bug report.

Jifl