Bug 69919 - pool allocator and mem-stat race at program exit
Summary: pool allocator and mem-stat race at program exit
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 6.0
: P3 normal
Target Milestone: ---
Assignee: Martin Liška
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-02-23 14:37 UTC by Richard Biener
Modified: 2016-02-25 16:58 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Suggested patch (995 bytes, patch)
2016-02-24 14:33 UTC, Martin Liška
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Biener 2016-02-23 14:37:44 UTC
==16301== Invalid read of size 8
==16301==    at 0x843457: mem_alloc_description<pool_usage>::release_instance_overhead(void*, unsigned long, bool) (mem-stats.h:513)
==16301==    by 0x8427C4: base_pool_allocator<memory_block_pool>::release() (alloc-pool.h:311)
==16301==    by 0x84299D: base_pool_allocator<memory_block_pool>::~base_pool_allocator() (alloc-pool.h:335)
==16301==    by 0x844E1B: object_allocator<cselib_val>::~object_allocator() (alloc-pool.h:474)
==16301==    by 0x5E13058: __run_exit_handlers (in /lib64/libc-2.18.so)
==16301==    by 0x5E130A4: exit (in /lib64/libc-2.18.so)
==16301==    by 0x5DFCBEB: (below main) (in /lib64/libc-2.18.so)
==16301==  Address 0x72529b0 is 1,088 bytes inside a block of size 3,048 free'd
==16301==    at 0x4C28ADC: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==16301==    by 0x844C81: xcallocator<hash_map<void const*, mem_usage_pair<pool_usage>, simple_hashmap_traits<default_hash_traits<void const*>, mem_usage_pair<pool_usage> > >::hash_entry>::data_free(hash_map<void const*, mem_usage_pair<pool_usage>, simple_hashmap_traits<default_hash_traits<void const*>, mem_usage_pair<pool_usage> > >::hash_entry*) (hash-table.h:273)
==16301==    by 0x14DC512: hash_table<hash_map<void const*, mem_usage_pair<pool_usage>, simple_hashmap_traits<default_hash_traits<void const*>, mem_usage_pair<pool_usage> > >::hash_entry, xcallocator>::~hash_table() (hash-table.h:627)
==16301==    by 0x14DCD77: hash_map<void const*, mem_usage_pair<pool_usage>, simple_hashmap_traits<default_hash_traits<void const*>, mem_usage_pair<pool_usage> > >::~hash_map() (hash-map.h:26)
==16301==    by 0x14DCE52: mem_alloc_description<pool_usage>::~mem_alloc_description() (mem-stats.h:559)
==16301==    by 0x5E13058: __run_exit_handlers (in /lib64/libc-2.18.so)
==16301==    by 0x5E130A4: exit (in /lib64/libc-2.18.so)
==16301==    by 0x5DFCBEB: (below main) (in /lib64/libc-2.18.so)
Comment 1 Richard Biener 2016-02-23 14:47:51 UTC
Too much C++ here I guess?

==16301==    by 0x14DCE52: mem_alloc_description<pool_usage>::~mem_alloc_description() (mem-stats.h:559)

vs.

==16301==    by 0x8427C4: base_pool_allocator<memory_block_pool>::release() (alloc-pool.h:311)
==16301==    by 0x84299D: base_pool_allocator<memory_block_pool>::~base_pool_allocator() (alloc-pool.h:335)
==16301==    by 0x8E25D3: object_allocator<et_occ>::~object_allocator() (alloc-pool.h:474)

where the latter calls release_instance_overhead.

extern mem_alloc_description<pool_usage> pool_allocator_usage;

comes from alloc-pool.c.  Looks like when linking LTO we get the bad destructor
order (by luck?).

Leaking pool_allocator_usage will fix this (making it a reference).  A very
bit ugly though.

Index: gcc/alloc-pool.c
===================================================================
--- gcc/alloc-pool.c    (revision 233633)
+++ gcc/alloc-pool.c    (working copy)
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3.
 #include "alloc-pool.h"
 
 ALLOC_POOL_ID_TYPE last_id;
-mem_alloc_description<pool_usage> pool_allocator_usage;
+mem_alloc_description<pool_usage> &pool_allocator_usage = *(new mem_alloc_description<pool_usage>);
 
 /* Output per-alloc_pool memory usage statistics.  */
 void
Index: gcc/alloc-pool.h
===================================================================
--- gcc/alloc-pool.h    (revision 233633)
+++ gcc/alloc-pool.h    (working copy)
@@ -95,7 +95,7 @@ struct pool_usage: public mem_usage
   const char *m_pool_name;
 };
 
-extern mem_alloc_description<pool_usage> pool_allocator_usage;
+extern mem_alloc_description<pool_usage> &pool_allocator_usage;
 
 #if 0
 /* If a pool with custom block size is needed, one might use the following
Comment 2 Richard Biener 2016-02-23 15:13:55 UTC
Or maybe simply making mem_alloc_description::~mem_alloc_description () empty.
Comment 3 Martin Liška 2016-02-24 14:33:50 UTC
Created attachment 37782 [details]
Suggested patch

Well, the situation is not so easy. Ideally, I would set m_reverse_map = NULL in
mem_alloc_description<T>::~mem_alloc_description () and guard release_object_overhead and release_instance_overhead with probes if m_* != NULL.

But as the assignment in the dtor is optimized out by DSE, because it's undefined to check member of a destroyed instance.

Thus I suggest a small work-around that can survive lto.exp and LTO bootstrap goes to stage3 (still running).

What do you think about it?
Comment 4 rguenther@suse.de 2016-02-24 14:46:25 UTC
On Wed, 24 Feb 2016, marxin at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69919
> 
> --- Comment #3 from Martin Liška <marxin at gcc dot gnu.org> ---
> Created attachment 37782 [details]
>   --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=37782&action=edit
> Suggested patch
> 
> Well, the situation is not so easy. Ideally, I would set m_reverse_map = NULL
> in
> mem_alloc_description<T>::~mem_alloc_description () and guard
> release_object_overhead and release_instance_overhead with probes if m_* !=
> NULL.
> 
> But as the assignment in the dtor is optimized out by DSE, because it's
> undefined to check member of a destroyed instance.
> 
> Thus I suggest a small work-around that can survive lto.exp and LTO bootstrap
> goes to stage3 (still running).
> 
> What do you think about it?

I guess it'll work.
Comment 5 Martin Liška 2016-02-25 16:58:10 UTC
Author: marxin
Date: Thu Feb 25 16:57:39 2016
New Revision: 233722

URL: https://gcc.gnu.org/viewcvs?rev=233722&root=gcc&view=rev
Log:
Do not gather mem stats in run_exit_handles (PR

	PR middle-end/69919
	* alloc-pool.c (after_memory_report): New variable.
	* alloc-pool.h (base_pool_allocator ::release): Do not use
	the infrastructure if after_memory_report.
	* toplev.c (toplev::main): Mark after memory report.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/alloc-pool.c
    trunk/gcc/alloc-pool.h
    trunk/gcc/toplev.c
Comment 6 Martin Liška 2016-02-25 16:58:47 UTC
Fixed in trunk.