caution about MELT & GCC passes & stuff at all passes end time...

23 views
Skip to first unread message

Basile Starynkevitch

unread,
Dec 13, 2012, 3:40:09 PM12/13/12
to gcc-...@googlegroups.com, emmanuel...@cea.fr
Hello All, and notably my colleague Emmanuel Haucourt

Emmanuel Haucourt is coding an alcool2melt.melt thing (which should extract some information, notably part of the control flow graph, and send a protocol describing it to his Alcool tool detecting deadlocks in parallel code using difficult topological algebra).

Emmanuel told me that later that alcool2melt.melt code might be released with some free software license (but it is not yet, so unfortunately I won't show all his code.). Actually I wish it would be published soon... (because I love MELT examples).


He made cc1 (the one in Ubuntu 12.04 from gcc-4.7) crash.

I had pains reproducing his bug (because getting an Ubuntu gcc-4.7 with
debugging information is damn difficult to me; to Debian & Ubuntu developpers:
please make a gcc-4.7-dbg package providing the debugging information of
gcc-4.7 -and its cc1- for GCC plugin developers!), but I finally caught it
on the MELT branch; here is the backtrace, the SIGSEGV is triggered by a
(debug "alcool_finalize alcooldata=" alcooldata)
in alcool2melt.melt line 417
and that alcooldata is an instance of some class_alcool_data with a field which is a map of edges.
The point is that edges are no longer valid when a function installed with register_all_passes_end_hook_first is called thru PLUGIN_ALL_PASSES_END

!!!!****####48#^4:melt2alcool.melt:417: !1: alcool_finalize alcooldata= |CLASS_ALCOOL_DATA/23d95a56{
ALCOOL_SEEN= !treemap.DISCR_MAP_TREES/1!{
* <function_decl 0x7ffff3204200 eat> == $:TRUE/225c7889 }!

ALCOOL_FUNCTIONS= !treemap.DISCR_MAP_TREES/1!{
* <function_decl 0x7ffff3204200 eat> == |CLASS_ALCOOL_OBJECT/3c67c116{ ALCOOL_NUMBER= #'1
ALCOOL_STUFF= ?/DISCR_TREE/{ <function_decl 0x7ffff3204200 eat>}/
} }!

ALCOOL_BASIC_BLOCKS= !bbmap.DISCR_MAP_BASIC_BLOCKS/1!{
*basicblock ix3_; == |CLASS_ALCOOL_OBJECT/143df221{ ALCOOL_NUMBER= #'1
ALCOOL_STUFF= ?/DISCR_BASIC_BLOCK/{
basicblock ix3_;}/
}}!

ALCOOL_GIMPLES= !gimplemap.DISCR_MAP_GIMPLES/2!{
*[square_on_torus.c : 20:21] pthread_mutex_lock ([square_on_torus.c : 20] &a_mutex);
== |CLASS_ALCOOL_OBJECT/3bccff00{ ALCOOL_NUMBER= #'1
ALCOOL_STUFF= ?/DISCR_GIMPLE/{[square_on_torus.c : 20:21] pthread_mutex_lock ([square_on_torus.c : 20] &a_mutex);
}/ }
*[square_on_torus.c : 22:23] pthread_mutex_unlock ([square_on_torus.c : 22] &a_mutex);
== |CLASS_ALCOOL_OBJECT/24a66d5b{ ALCOOL_NUMBER= #'2
ALCOOL_STUFF= ?/DISCR_GIMPLE/{[square_on_torus.c : 22:23] pthread_mutex_unlock ([square_on_torus.c : 22] &a_mutex);
}/ } }!

ALCOOL_EDGES= !edgemap.DISCR_MAP_EDGES/2!{
* 2 [100.0%] (FALLTHRU) == |CLASS_ALCOOL_OBJECT/17892d2f{ ALCOOL_NUMBER= #'1
ALCOOL_STUFF= ?/DISCR_EDGE/[ 2 [100.0%] (FALLTHRU)]/
}
*
Program received signal SIGSEGV, Segmentation fault.
dump_edge_info (file=0x7ffff6d4b880, e=0x7ffff31892a0, flags=<optimized out>, do_succ=1)
at /usr/src/Lang/basile-melt-gcc/gcc/cfg.c:465
465 if (side->index == ENTRY_BLOCK)
(gdb) bt
bt
#0 dump_edge_info (file=0x7ffff6d4b880, e=0x7ffff31892a0, flags=<optimized out>,
do_succ=1) at /usr/src/Lang/basile-melt-gcc/gcc/cfg.c:465
#1 0x00000000006111a9 in meltgc_out_edge (out_p=<optimized out>, edg=0x7ffff31892a0)
at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:12338
#2 0x00007ffff42eb583 in meltrout_24_xtramelt_ana_base_DBGOUT_MAPEDGE_METHOD(meltclosure_st*, melt_un*, char const*, meltparam_un*, char const*, meltparam_un*) ()
from /usr/local/libexec/gcc-melt/gcc/x86_64-unknown-linux-gnu/4.8.0/melt-modules/0.9.8-rc2/xtramelt-ana-base.meltmod-0fd3f0013f75c59a9bc53b8aa409216e.optimized.so
#3 0x000000000060d8f4 in melt_apply (clos_p=clos_p@entry=0x7ffff68b1b28,
arg1_p=arg1_p@entry=0x7ffff68d9b80,
xargdescr_=xargdescr_@entry=0x7ffff594cd18 "\f\a",
xargtab_=xargtab_@entry=0x7fffffffd250,
xresdescr_=xresdescr_@entry=0x7ffff5952a06 "", xrestab_=xrestab_@entry=0x0)
at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5135
#4 0x0000000000614c25 in meltgc_send (recv_p=<optimized out>, sel_p=<optimized out>,
xargdescr_=0x7ffff594cd18 "\f\a", xargtab_=0x7fffffffd250,
xresdescr_=0x7ffff5952a06 "", xrestab_=0x0)
at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5236
#5 0x00007ffff59363b3 in meltrout_10_warmelt_debug_DBG_OUT(meltclosure_st*, melt_un*, char const*, meltparam_un*, char const*, meltparam_un*) ()
from /usr/local/libexec/gcc-melt/gcc/x86_64-unknown-linux-gnu/4.8.0/melt-modules/0.9.8-rc2/warmelt-debug.meltmod-86a1093472081c61622001e66e2f45af.optimized.so
#6 0x000000000060d8f4 in melt_apply (clos_p=0x7ffff682c5d0, arg1_p=<optimized out>,
xargdescr_=<optimized out>, xargtab_=<optimized out>, xresdescr_=<optimized out>,
xrestab_=<optimized out>) at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5135
#7 0x00007ffff5937342 in meltrout_11_warmelt_debug_DBGOUT_FIELDS(meltclosure_st*, melt_un*, char const*, meltparam_un*, char const*, meltparam_un*) ()
from /usr/local/libexec/gcc-melt/gcc/x86_64-unknown-linux-gnu/4.8.0/melt-modules/0.9.8-rc2/warmelt-debug.meltmod-86a1093472081c61622001e66e2f45af.optimized.so
#8 0x000000000060d8f4 in melt_apply (clos_p=0x7ffff682cd80, arg1_p=<optimized out>,
xargdescr_=<optimized out>, xargtab_=<optimized out>, xresdescr_=<optimized out>,
xrestab_=<optimized out>) at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5135
#9 0x00007ffff5945603 in meltrout_35_warmelt_debug_DBGOUT_ANYOBJECT_METHOD(meltclosure_st*, melt_un*, char const*, meltparam_un*, char const*, meltparam_un*) ()
from /usr/local/libexec/gcc-melt/gcc/x86_64-unknown-linux-gnu/4.8.0/melt-modules/0.9.8-rc2/warmelt-debug.meltmod-86a1093472081c61622001e66e2f45af.optimized.so
#10 0x000000000060d8f4 in melt_apply (clos_p=clos_p@entry=0x7ffff682ced0,
arg1_p=arg1_p@entry=0x7ffff68bd910,
xargdescr_=xargdescr_@entry=0x7ffff594cd18 "\f\a",
xargtab_=xargtab_@entry=0x7fffffffd880,
xresdescr_=xresdescr_@entry=0x7ffff5952a06 "", xrestab_=xrestab_@entry=0x0)
at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5135
#11 0x0000000000614c25 in meltgc_send (recv_p=<optimized out>, sel_p=<optimized out>,
xargdescr_=0x7ffff594cd18 "\f\a", xargtab_=0x7fffffffd880,
xresdescr_=0x7ffff5952a06 "", xrestab_=0x0)
at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5236
#12 0x00007ffff5935b43 in meltrout_9_warmelt_debug_DBG_OUTOBJECT(meltclosure_st*, melt_un*, char const*, meltparam_un*, char const*, meltparam_un*) ()
from /usr/local/libexec/gcc-melt/gcc/x86_64-unknown-linux-gnu/4.8.0/melt-modules/0.9.8-rc2/warmelt-debug.meltmod-86a1093472081c61622001e66e2f45af.optimized.so
#13 0x000000000060d8f4 in melt_apply (clos_p=0x7ffff682c708, arg1_p=<optimized out>,
xargdescr_=<optimized out>, xargtab_=<optimized out>, xresdescr_=<optimized out>,
xrestab_=<optimized out>) at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5135
#14 0x00007ffff593630c in meltrout_10_warmelt_debug_DBG_OUT(meltclosure_st*, melt_un*, char const*, meltparam_un*, char const*, meltparam_un*) ()
from /usr/local/libexec/gcc-melt/gcc/x86_64-unknown-linux-gnu/4.8.0/melt-modules/0.9.8-rc2/warmelt-debug.meltmod-86a1093472081c61622001e66e2f45af.optimized.so
#15 0x000000000060d8f4 in melt_apply (clos_p=0x7ffff682c5d0, arg1_p=<optimized out>,
xargdescr_=<optimized out>, xargtab_=<optimized out>, xresdescr_=<optimized out>,
xrestab_=<optimized out>) at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5135
#16 0x00007ffff593409b in meltrout_8_warmelt_debug_MELT_DEBUG_FUN(meltclosure_st*, melt_un*, char const*, meltparam_un*, char const*, meltparam_un*) ()
from /usr/local/libexec/gcc-melt/gcc/x86_64-unknown-linux-gnu/4.8.0/melt-modules/0.9.8-rc2/warmelt-debug.meltmod-86a1093472081c61622001e66e2f45af.optimized.so
#17 0x000000000060d8f4 in melt_apply (clos_p=0x7ffff682c5a0, arg1_p=<optimized out>,
xargdescr_=<optimized out>, xargtab_=<optimized out>, xresdescr_=<optimized out>,
xrestab_=<optimized out>) at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5135
#18 0x00007ffff2c6552a in meltrout_11_melt2alcool_ALCOOL_FINALIZE(meltclosure_st*, melt_un*, char const*, meltparam_un*, char const*, meltparam_un*) ()
from /home/basile/tmp/melt_to_alcool/meltworkdir/melt2alcool.meltmod-ec9513c7939be9f163b921634b5a688f.quicklybuilt.so
#19 0x000000000060d8f4 in melt_apply (clos_p=0x7ffff68da3a8, arg1_p=<optimized out>,
xargdescr_=<optimized out>, xargtab_=<optimized out>, xresdescr_=<optimized out>,
xrestab_=<optimized out>) at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5135
#20 0x00007ffff2c67f08 in meltrout_14_melt2alcool_LAMBDA___3__(meltclosure_st*, melt_un*, char const*, meltparam_un*, char const*, meltparam_un*) ()
from /home/basile/tmp/melt_to_alcool/meltworkdir/melt2alcool.meltmod-ec9513c7939be9f163b921634b5a688f.quicklybuilt.so
#21 0x000000000060d8f4 in melt_apply (clos_p=0x7ffff68d9ae0, arg1_p=<optimized out>,
xargdescr_=<optimized out>, xargtab_=<optimized out>, xresdescr_=<optimized out>,
xrestab_=<optimized out>) at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5135
#22 0x00007ffff5c96fdc in meltrout_40_warmelt_base_MELT_ALL_PASSES_END_RUNNER(meltclosure_st*, melt_un*, char const*, meltparam_un*, char const*, meltparam_un*) ()
from /usr/local/libexec/gcc-melt/gcc/x86_64-unknown-linux-gnu/4.8.0/melt-modules/0.9.8-rc2/warmelt-base.meltmod-5d968a5dcbc4cfca5e06e1648c6e6028.optimized.so
#23 0x000000000060d8f4 in melt_apply (clos_p=0x7ffff68000a8, arg1_p=arg1_p@entry=0x0,
xargdescr_=xargdescr_@entry=0xf48130 "", xargtab_=xargtab_@entry=0x0,
xresdescr_=xresdescr_@entry=0xf48130 "", xrestab_=xrestab_@entry=0x0)
at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:5135
#24 0x00000000006162d7 in meltgc_all_passes_end_callback (gcc_data=<optimized out>,
user_data=<optimized out>) at /usr/src/Lang/basile-melt-gcc/gcc/melt-runtime.c:8935
#25 0x00000000008d11da in invoke_plugin_callbacks_full (event=<optimized out>,
gcc_data=0x0) at /usr/src/Lang/basile-melt-gcc/gcc/plugin.c:526
#26 0x00000000006a4b54 in invoke_plugin_callbacks (event=16, gcc_data=<optimized out>)
at /usr/src/Lang/basile-melt-gcc/gcc/plugin.h:59
#27 expand_function (node=0x7ffff315b818)
at /usr/src/Lang/basile-melt-gcc/gcc/cgraphunit.c:1644
#28 0x00000000006a673d in expand_all_functions ()
at /usr/src/Lang/basile-melt-gcc/gcc/cgraphunit.c:1745
#29 compile () at /usr/src/Lang/basile-melt-gcc/gcc/cgraphunit.c:2043
#30 0x00000000006a6dd5 in finalize_compilation_unit ()
at /usr/src/Lang/basile-melt-gcc/gcc/cgraphunit.c:2120
#31 0x000000000054ce43 in c_write_global_declarations ()
at /usr/src/Lang/basile-melt-gcc/gcc/c/c-decl.c:10120
#32 0x00000000009752a5 in compile_file ()
at /usr/src/Lang/basile-melt-gcc/gcc/toplev.c:571
#33 0x0000000000976f4a in do_compile ()
at /usr/src/Lang/basile-melt-gcc/gcc/toplev.c:1902
#34 toplev_main (argc=23, argv=0x7fffffffe4c8)
at /usr/src/Lang/basile-melt-gcc/gcc/toplev.c:1983
#35 0x00007ffff69e5ead in __libc_start_main (main=<optimized out>,
argc=<optimized out>, ubp_av=<optimized out>, init=<optimized out>,
fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe4b8)
at libc-start.c:228
#36 0x0000000000537b29 in _start ()



(gdb) p edg
p edg
$3 = (edge) 0x7ffff25d82a0
(gdb) p *edg
p *edg
$4 = {src = 0xa5a5a5a5a5a5a5a5, dest = 0xa5a5a5a5a5a5a5a5, insns = {
g = 0xa5a5a5a5a5a5a5a5, r = 0xa5a5a5a5a5a5a5a5}, aux = 0xa5a5a5a5a5a5a5a5,
goto_locus = 2779096485, dest_idx = 2779096485, flags = -1515870811,
probability = -1515870811, count = -6510615555426900571}

x /16x edg
0x7ffff25d82a0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0x7ffff25d82b0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0x7ffff25d82c0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
0x7ffff25d82d0: 0xa5a5a5a5 0xa5a5a5a5 0x00002003 0x00000000


And now, my (incomplete) analysis of what is probably happenning and why MELT
cannot help that much, so Emmanuel will probably have to change his code....

My GCC MELT branch is compiled with --enable-checking=gc

the 0xa5a5a5a5 is filled by the macro poison_region defined in gcc/ggc-zone.c of GCC 4.7
that macro is called (when enable-checking=gc is configured) by the GCC garbage collector when sweeping pages (e.g. by sweep_page in gcc/ggc-zone.c lines 2072 or 2119)

So in short Emmanuel is trying to access a GCC garbage-collected and freed zone which
used to be some edge.

What was Emmanuel trying to do (but I am only to blame, not him; because I gave him a bad advice)
was the following:

he has a single pass named "alcool" which is a simple Gimple pass (a direct instance of class_gcc_gimple_pass in MELT code) which is installed with the below code
(from function alcool_docmd which is for the alcool mode).

(let (
(alcooldata (instance class_alcool_data
:alcool_seen (make_maptree discr_map_trees 100)
:alcool_functions (make_maptree discr_map_trees 100)
:alcool_basic_blocks (make_mapbasicblock discr_map_basic_blocks 400)
:alcool_gimples (make_mapgimple discr_map_gimples 1000)
:alcool_edges (make_mapedge discr_map_edges 1000)
:alcool_threads (make_maptree discr_map_trees 20)
:alcool_mutex (make_maptree discr_map_trees 20)
:alcool_delayed (list)
)
)
(alcoolpass (instance class_gcc_gimple_pass
:named_name '"alcool_pass"
:gccpass_data alcooldata
:gccpass_exec alcool_pass_exec))
)
(install_melt_gcc_pass alcoolpass "after" "phiopt" 0)

That pass is (correctly) filling the alcooldata object.

But that alcooldata object is used with

(register_all_passes_end_hook_first (lambda () (alcool_finalize alcooldata)))

So the alcool_finalize MELT function (which is crashing with the debug expression
I mentioned earlier) is called thru PLUGIN_ALL_PASSES_END at a time where the Gimple representations (and its friends like edge-s) is dead.

GCC is forcibly releasing its memory. Several occurrence of ggc_free appear inside the GCC source code. Sadly, GCC people don't like and don't trust very much their Ggc garbage collector (and if you read the garbage collector exchanges on the g...@gcc.gnu.org list, this won't change; a lot of GCC people want to get rid of the Ggc, which IMNSHO is a huge mistake).

So what is happenning is that middle-end information (like Gimple & Edge) was killed, but still accessed by Emmanuel's code after all passes have ended -ie at PLUGIN_ALL_PASSES_END time. And this crashes, and I cannot help much.

A possible workaround for Emmanuel might be call instead of register_all_passes_end_hook_first the MELT function register_all_ipa_passes_start_hook_first because his alcool_finalize function just wants to print the middle end representations, so he should not print them after the middle-end & the back-end have finished, but only after all IPA -interprocedural analysis- passes have been done.

But the real lesson of this is that my motto: "Prefer MELT values to GCC stuff" is really significant.
GCC stuff can forcibly die (because GCC might kill them forcibly, outside of Ggc), and a plugin (e.G. MELT) cannot help much about that. Emmanuel is (by my bad advice) abusing GCC. Don't use MELT to have some GCC stuff
outliving its intended life (and the life of Gimple and other middle-end representations stops at the beginning of the back-end, e.g. in RTL passes). If you really require some Gcc middle-end stuff to live past the middle-end, do at least a *deep* copy of it -e.g. using gimple_copy and friends, but that is painful, because edge & CFG information also should be duplicated....).

My public apologies to Emmanuel for having given such a wrong advice.

I don't think I can reasonably do much more about this bug. Emmanuel was (by my wrong advice) violating some deep (but not-well documented) invariant of GCC, that middle-end representations does not stay alive in the back-end so cannot be used at PLUGIN_ALL_PASSES_END time.


Regards.


--
Basile STARYNKEVITCH http://starynkevitch.net/Basile/
email: basile<at>starynkevitch<dot>net mobile: +33 6 8501 2359
8, rue de la Faiencerie, 92340 Bourg La Reine, France
*** opinions {are only mines, sont seulement les miennes} ***

Basile Starynkevitch

unread,
Dec 14, 2012, 9:22:12 AM12/14/12
to gcc-...@googlegroups.com, emmanuel...@cea.fr
On Thu, Dec 13, 2012 at 09:40:09PM +0100, Basile Starynkevitch wrote:
> Hello All, and notably my colleague Emmanuel Haucourt
>
> So in short Emmanuel is trying to access a GCC garbage-collected and freed zone which
> used to be some edge.

I can confirm that. Edges are *explicitly* destroyed by the pass_expand
(an RTL_PASS, i.e. a back-end pass, not a middle-end one, defined line 4793
of file gcc/cfgexpand.c in the GCC trunk), which indirectly call explicitly free_edge ....

#0 __memset_sse2 () at ../sysdeps/x86_64/multiarch/../memset.S:334
#1 0x000000000059d89e in ggc_free (p=0x7ffff27762a0)
at /usr/src/Lang/basile-melt-gcc/gcc/ggc-page.c:1554
#2 0x0000000000620a68 in free_edge (e=e@entry=0x7ffff27762a0)
at /usr/src/Lang/basile-melt-gcc/gcc/cfg.c:94
#3 0x00000000006214d1 in remove_edge_raw (e=0x7ffff27762a0)
at /usr/src/Lang/basile-melt-gcc/gcc/cfg.c:353
#4 0x00000000006352ae in remove_edge (e=0x7ffff27762a0)
at /usr/src/Lang/basile-melt-gcc/gcc/cfghooks.c:396
#5 0x0000000000635d7b in merge_blocks (a=0x7ffff27fa888, b=0x7ffff27fa8f0)
at /usr/src/Lang/basile-melt-gcc/gcc/cfghooks.c:746
#6 0x0000000000d5c867 in merge_blocks_move (mode=16, c=0x7ffff27fa8f0,
b=0x7ffff27fa888, e=<optimized out>)
at /usr/src/Lang/basile-melt-gcc/gcc/cfgcleanup.c:789
#7 try_optimize_cfg (mode=16)
at /usr/src/Lang/basile-melt-gcc/gcc/cfgcleanup.c:2738
#8 cleanup_cfg (mode=16)
at /usr/src/Lang/basile-melt-gcc/gcc/cfgcleanup.c:2978
#9 0x000000000063406d in gimple_expand_cfg ()
at /usr/src/Lang/basile-melt-gcc/gcc/cfgexpand.c:4722
#10 0x0000000000882864 in execute_one_pass (pass=pass@entry=0x1481780)


> A possible workaround for Emmanuel might be call instead of register_all_passes_end_hook_first the MELT function register_all_ipa_passes_start_hook_first because his alcool_finalize function just wants to print the middle end representations, so he should not print them after the middle-end & the back-end have finished, but only after all IPA -interprocedural analysis- passes have been done.


I cannot help more about such bugs. GCC is forcibly cleaning its memory once the back-end is starting, and plugins
are not expected to refer to middle-end stuff at that time.

Cheers.
Reply all
Reply to author
Forward
0 new messages