diff mbox

libstdc++/69945 Add __gnu_cxx::__freeres hook

Message ID 20160224183558.GF4664@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Feb. 24, 2016, 6:35 p.m. UTC
This adds a new function to libsupc++ which will free the memory still
in use by the pool used for allocating exceptions when malloc fails.

This is similar to glibc's __libc_freeres, which valgrind (and other
tools?) use to tell glibc to deallocate everything before exiting.

I initially called it __gnu_cxx::__free_eh_pool() but I figured we
might have other memory in use at some later date, and we wouldn't
want valgrind to have to start calling a second function, nor make a
function called __free_eh_pool() actually free other things.

I intentionally *didn't* lock the pool's mutex before freeing it,
because this should never be called in a context where multiple
threads are still active and accessing the pool.

Thoughts?

Is the new test a good idea, or will exposing it like that in the
testsuite just give users the idea that they can/should be doing the
same themselves?


[ Aside: should the actual pool be created with placement-new to
[ ensure it doesn't ever get destroyed?
[
[   alignas(pool) unsigned char poolbuf[sizeof(pool)];
[   pool& emergency_pool = *::new(poolbuf) pool;

Comments

Richard Biener Feb. 25, 2016, 9:36 a.m. UTC | #1
On Wed, Feb 24, 2016 at 7:35 PM, Jonathan Wakely <jwakely@redhat.com> wrote:
> This adds a new function to libsupc++ which will free the memory still
> in use by the pool used for allocating exceptions when malloc fails.
>
> This is similar to glibc's __libc_freeres, which valgrind (and other
> tools?) use to tell glibc to deallocate everything before exiting.
>
> I initially called it __gnu_cxx::__free_eh_pool() but I figured we
> might have other memory in use at some later date, and we wouldn't
> want valgrind to have to start calling a second function, nor make a
> function called __free_eh_pool() actually free other things.
>
> I intentionally *didn't* lock the pool's mutex before freeing it,
> because this should never be called in a context where multiple
> threads are still active and accessing the pool.
>
> Thoughts?
>
> Is the new test a good idea, or will exposing it like that in the
> testsuite just give users the idea that they can/should be doing the
> same themselves?

The goal is to lookup the function via dlsym and only call it before
glibcs freeres (which will probably make free() in-operatable?)

>
> [ Aside: should the actual pool be created with placement-new to
> [ ensure it doesn't ever get destroyed?
> [
> [   alignas(pool) unsigned char poolbuf[sizeof(pool)];
> [   pool& emergency_pool = *::new(poolbuf) pool;

Hmm, for pedantic correctness yes I guess.  But it hasn't any destructor,
it's global (so no CLOBBER / memory re-use issue) and so the destruction
won't do anything.  Of course it might simply save a global dtor (does it
even register one?  I don't see one).

There is still the missing feature of allowing to size the emergency
pool using an environment variable (properly securely implemented, of course).

Richard.

>
>
Jonathan Wakely Feb. 25, 2016, 9:50 a.m. UTC | #2
On 25/02/16 10:36 +0100, Richard Biener wrote:
>On Wed, Feb 24, 2016 at 7:35 PM, Jonathan Wakely <jwakely@redhat.com> wrote:
>> This adds a new function to libsupc++ which will free the memory still
>> in use by the pool used for allocating exceptions when malloc fails.
>>
>> This is similar to glibc's __libc_freeres, which valgrind (and other
>> tools?) use to tell glibc to deallocate everything before exiting.
>>
>> I initially called it __gnu_cxx::__free_eh_pool() but I figured we
>> might have other memory in use at some later date, and we wouldn't
>> want valgrind to have to start calling a second function, nor make a
>> function called __free_eh_pool() actually free other things.
>>
>> I intentionally *didn't* lock the pool's mutex before freeing it,
>> because this should never be called in a context where multiple
>> threads are still active and accessing the pool.
>>
>> Thoughts?
>>
>> Is the new test a good idea, or will exposing it like that in the
>> testsuite just give users the idea that they can/should be doing the
>> same themselves?
>
>The goal is to lookup the function via dlsym and only call it before
>glibcs freeres (which will probably make free() in-operatable?)

Yes, I believe so (Mark? Ivo?)

Another way to test it would be to use dg-final to run gdb in the
global's destructor and try to call the function from GDB.

>>
>> [ Aside: should the actual pool be created with placement-new to
>> [ ensure it doesn't ever get destroyed?
>> [
>> [   alignas(pool) unsigned char poolbuf[sizeof(pool)];
>> [   pool& emergency_pool = *::new(poolbuf) pool;
>
>Hmm, for pedantic correctness yes I guess.  But it hasn't any destructor,
>it's global (so no CLOBBER / memory re-use issue) and so the destruction
>won't do anything.  Of course it might simply save a global dtor (does it
>even register one?  I don't see one).

It was the CLOBBER that I was thinking about, but I agree we don't
(currently) do that for trivial destructors.

>There is still the missing feature of allowing to size the emergency
>pool using an environment variable (properly securely implemented, of course).

Yes.
Mark Wielaard March 3, 2016, 3:34 p.m. UTC | #3
On Wed, 2016-02-24 at 18:35 +0000, Jonathan Wakely wrote:
> This adds a new function to libsupc++ which will free the memory still
> in use by the pool used for allocating exceptions when malloc fails.
> 
> This is similar to glibc's __libc_freeres, which valgrind (and other
> tools?) use to tell glibc to deallocate everything before exiting.
> 
> I initially called it __gnu_cxx::__free_eh_pool() but I figured we
> might have other memory in use at some later date, and we wouldn't
> want valgrind to have to start calling a second function, nor make a
> function called __free_eh_pool() actually free other things.

I tested this on x86_64-pc-linux-gnu with Ivo's valgrind patch from
https://bugs.kde.org/show_bug.cgi?id=345307 and it works pretty nicely.
No more spurious still reachable memory issues with memcheck.

Is there any possibility to get this backported for 5.4?

Thanks,

Mark
Mark Wielaard March 16, 2016, 3:29 p.m. UTC | #4
On Thu, 2016-03-03 at 16:34 +0100, Mark Wielaard wrote:
> On Wed, 2016-02-24 at 18:35 +0000, Jonathan Wakely wrote:
> > This adds a new function to libsupc++ which will free the memory still
> > in use by the pool used for allocating exceptions when malloc fails.
> > 
> > This is similar to glibc's __libc_freeres, which valgrind (and other
> > tools?) use to tell glibc to deallocate everything before exiting.
> > 
> > I initially called it __gnu_cxx::__free_eh_pool() but I figured we
> > might have other memory in use at some later date, and we wouldn't
> > want valgrind to have to start calling a second function, nor make a
> > function called __free_eh_pool() actually free other things.
> 
> I tested this on x86_64-pc-linux-gnu with Ivo's valgrind patch from
> https://bugs.kde.org/show_bug.cgi?id=345307 and it works pretty nicely.
> No more spurious still reachable memory issues with memcheck.
> 
> Is there any possibility to get this backported for 5.4?

If there is anything I can do to help move this patch forward, please
let me know.

Thanks,

Mark
Jonathan Wakely March 24, 2016, 6:14 p.m. UTC | #5
On 16/03/16 16:29 +0100, Mark Wielaard wrote:
>On Thu, 2016-03-03 at 16:34 +0100, Mark Wielaard wrote:
>> On Wed, 2016-02-24 at 18:35 +0000, Jonathan Wakely wrote:
>> > This adds a new function to libsupc++ which will free the memory still
>> > in use by the pool used for allocating exceptions when malloc fails.
>> >
>> > This is similar to glibc's __libc_freeres, which valgrind (and other
>> > tools?) use to tell glibc to deallocate everything before exiting.
>> >
>> > I initially called it __gnu_cxx::__free_eh_pool() but I figured we
>> > might have other memory in use at some later date, and we wouldn't
>> > want valgrind to have to start calling a second function, nor make a
>> > function called __free_eh_pool() actually free other things.
>>
>> I tested this on x86_64-pc-linux-gnu with Ivo's valgrind patch from
>> https://bugs.kde.org/show_bug.cgi?id=345307 and it works pretty nicely.
>> No more spurious still reachable memory issues with memcheck.
>>
>> Is there any possibility to get this backported for 5.4?
>
>If there is anything I can do to help move this patch forward, please
>let me know.

Sorry for stalling, other things distracted me. It's committed to
trunk now though.
diff mbox

Patch

commit 40fed1db72b0a4852d5890c2c464a0baabb02b74
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Feb 24 18:22:30 2016 +0000

    libstdc++/69945 Add __gnu_cxx::__freeres hook
    
    	* config/abi/pre/gnu.ver: Add new symbol.
    	* libsupc++/eh_alloc.cc (__gnu_cxx::__freeres): Define.
    	* testsuite/18_support/free_eh_pool.cc: New test.

diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 41069d1..5c6b0fe 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -2148,6 +2148,8 @@  CXXABI_1.3.10 {
     _ZGTtNKSt13bad_exceptionD1Ev;
     _ZGTtNKSt13bad_exception4whatEv;
 
+    _ZN9__gnu_cxx9__freeresEv;
+
 } CXXABI_1.3.9;
 
 # Symbols in the support library (libsupc++) supporting transactional memory.
diff --git a/libstdc++-v3/libsupc++/eh_alloc.cc b/libstdc++-v3/libsupc++/eh_alloc.cc
index 6973af3..d362e40 100644
--- a/libstdc++-v3/libsupc++/eh_alloc.cc
+++ b/libstdc++-v3/libsupc++/eh_alloc.cc
@@ -73,6 +73,10 @@  using namespace __cxxabiv1;
 # define EMERGENCY_OBJ_COUNT	4
 #endif
 
+namespace __gnu_cxx
+{
+  void __freeres();
+}
 
 namespace
 {
@@ -106,6 +110,8 @@  namespace
       // to implement in_pool.
       char *arena;
       std::size_t arena_size;
+
+      friend void __gnu_cxx::__freeres();
     };
 
   pool::pool()
@@ -244,6 +250,19 @@  namespace
   pool emergency_pool;
 }
 
+namespace __gnu_cxx
+{
+  void
+  __freeres()
+  {
+    if (emergency_pool.arena)
+      {
+	::free(emergency_pool.arena);
+	emergency_pool.arena = 0;
+      }
+  }
+}
+
 extern "C" void *
 __cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) _GLIBCXX_NOTHROW
 {
diff --git a/libstdc++-v3/testsuite/18_support/free_eh_pool.cc b/libstdc++-v3/testsuite/18_support/free_eh_pool.cc
new file mode 100644
index 0000000..9712d3d
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/free_eh_pool.cc
@@ -0,0 +1,35 @@ 
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run }
+
+namespace __gnu_cxx {
+  void __freeres();
+}
+
+struct X {
+  ~X() {
+    __gnu_cxx::__freeres();
+  }
+};
+
+X x;
+
+int
+main()
+{
+}