https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105769
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jakub at gcc dot gnu.org --- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> --- At least when using g++ 12.1.1 (20220507), the crash is because the stack slot holding return value from jacknife is clobbered on the bias = est(map); line. I see in main (well, print_cov_ratio and std::function inlined into it): 0x00000000004016d1 <main()+274>: lea 0x50(%rsp),%rsi 0x00000000004016d6 <main()+279>: lea 0x30(%rsp),%rdi => 0x00000000004016db <main()+284>: call *0x48(%rsp) 0x00000000004016df <main()+288>: jmp 0x401742 <main()+387> where 0x30(%rsp) seems to be the est argument to jacknife (32 byte est_t) and 0x50(%rsp) the return value from jacknife (32 byte est_t) (gdb) p/x $rsp+0x50 $49 = 0x7fffffffdd20 where the indirect call calls: #0 std::_Function_handler<void (std::function<unsigned long (unsigned long)>), jacknife<2ul, ab>(std::function<vec<2ul, ab> (std::function<unsigned long (unsigned long)>)>, vec<2ul, vec<2ul, ab> >&, vec<2ul, ab>&)::{lambda(std::function<unsigned long (unsigned long)>)#1}>::_M_invoke(std::_Any_data const&, std::function<unsigned long (unsigned long)>&&) ( __functor=..., __args#0=...) at /usr/include/c++/12/bits/std_function.h:288 #1 0x00000000004016df in std::function<void (std::function<unsigned long (unsigned long)>)>::operator()(std::function<unsigned long (unsigned long)>) const (__args#0=..., this=0x7fffffffdd00) at /usr/include/c++/12/bits/std_function.h:591 #2 print_cov_ratio<ab> () at /usr/src/gcc/obj/gcc/pr105769.C:85 #3 main () at /usr/src/gcc/obj/gcc/pr105769.C:121 But later in #0 0x00000000004014f3 in jacknife<2ul, ab>(std::function<vec<2ul, ab> (std::function<unsigned long (unsigned long)>)>, vec<2ul, vec<2ul, ab> >&, vec<2ul, ab>&)::{lambda(std::function<unsigned long (unsigned long)>)#1}::operator()(std::function<unsigned long (unsigned long)>) const (map=..., __closure=0x4172c0) at /usr/src/gcc/obj/gcc/pr105769.C:59 #1 std::__invoke_impl<void, jacknife<2ul, ab>(std::function<vec<2ul, ab> (std::function<unsigned long (unsigned long)>)>, vec<2ul, vec<2ul, ab> >&, vec<2ul, ab>&)::{lambda(std::function<unsigned long (unsigned long)>)#1}&, std::function<unsigned long (unsigned long)> >(std::__invoke_other, jacknife<2ul, ab>(std::function<vec<2ul, ab> (std::function<unsigned long (unsigned long)>)>, vec<2ul, vec<2ul, ab> >&, vec<2ul, ab>&)::{lambda(std::function<unsigned long (unsigned long)>)#1}&, std::function<unsigned long (unsigned long)>&&) (__f=...) at /usr/include/c++/12/bits/invoke.h:61 #2 std::__invoke_r<void, jacknife<2ul, ab>(std::function<vec<2ul, ab> (std::function<unsigned long (unsigned long)>)>, vec<2ul, vec<2ul, ab> >&, vec<2ul, ab>&)::{lambda(std::function<unsigned long (unsigned long)>)#1}&, std::function<unsigned long (unsigned long)> >(jacknife<2ul, ab>(std::function<vec<2ul, ab> (std::function<unsigned long (unsigned long)>)>, vec<2ul, vec<2ul, ab> >&, vec<2ul, ab>&)::{lambda(std::function<unsigned long (unsigned long)>)#1}&, std::function<unsigned long (unsigned long)>&&) (__fn=...) at /usr/include/c++/12/bits/invoke.h:111 #3 std::_Function_handler<void (std::function<unsigned long (unsigned long)>), jacknife<2ul, ab>(std::function<vec<2ul, ab> (std::function<unsigned long (unsigned long)>)>, vec<2ul, vec<2ul, ab> >&, vec<2ul, ab>&)::{lambda(std::function<unsigned long (unsigned long)>)#1}>::_M_invoke(std::_Any_data const&, std::function<unsigned long (unsigned long)>&&) ( __functor=..., __args#0=...) at /usr/include/c++/12/bits/std_function.h:290 #4 0x00000000004016df in std::function<void (std::function<unsigned long (unsigned long)>)>::operator()(std::function<unsigned long (unsigned long)>) const (__args#0=..., this=0x7fffffffdd00) at /usr/include/c++/12/bits/std_function.h:591 #5 print_cov_ratio<ab> () at /usr/src/gcc/obj/gcc/pr105769.C:85 #6 main () at /usr/src/gcc/obj/gcc/pr105769.C:121 &bias is equal to the address of the jacknife return value: $50 = (vec<2, ab> *) 0x7fffffffdd20 To make the dumps more readable, I've patched the testcase: --- pr105769.C~ 2023-01-16 19:05:01.000000000 +0100 +++ pr105769.C 2023-01-16 20:38:25.101524077 +0100 @@ -40,7 +40,7 @@ using sq_mat = mat<n, n, T>; using map_t = std::function<size_t(size_t)>; template<class T_v> -using est_t = std::function<T_v(map_t map)>; +using est_t = std::function<T_v(map_t map)>; template<class T_v> using est2_t = std::function<T_v(map_t map)>; map_t id_map() { return [](size_t j) -> size_t { @@ -50,7 +50,7 @@ map_t id_map() { template<size_t n, class T> -est_t<void> jacknife(const est_t<vec<n, T>> est, +est2_t<void> jacknife(const est_t<vec<n, T>> est, sq_mat<n, T>& cov, vec<n, T>& bias) { return [est, &cov, &bias]( and with that in the *.gimple dump I see: void print_cov_ratio<ab> () [pr105769.C:88:1] { struct est2_t D.85904; struct est_t D.85869; struct ._anon_95 D.85344; struct map_t D.85939; struct sq_mat cov_jn; struct vec bias; typedef struct ._anon_95 ._anon_95; try { [pr105769.C:73:16] vec<2, vec<2, ab> >::vec ([pr105769.C:73:16] &cov_jn); [pr105769.C:74:13] vec<2, ab>::vec ([pr105769.C:74:13] &bias); [pr105769.C:85:23] try { try { try { [pr105769.C:85:23] std::function<vec<2, ab>(std::function<long unsigned int(long unsigned int)>)>::function<print_cov_ratio<ab>()::<lambda(map_t)> > ([pr105769.C:85 try { [pr105769.C:85:23] D.85904 = jacknife<2, ab> ([pr105769.C:85:23] &D.85869, [pr105769.C:85:10] &cov_jn, [pr105769.C:85:18] &bias); [return slot optimization] try { try { [pr105769.C:85:23] D.85939 = id_map (); [return slot optimization] try { [pr105769.C:85:23] std::function<void(std::function<long unsigned int(long unsigned int)>)>::operator() ([pr105769.C:85:23] &D.85904, [pr105769.C:85 } finally { [pr105769.C:85:23] std::function<long unsigned int(long unsigned int)>::~function ([pr105769.C:85:23] &D.85939); } } finally { [pr105769.C:85:23] D.85939 = {CLOBBER(eol)}; } } finally { [pr105769.C:85:23] std::function<void(std::function<long unsigned int(long unsigned int)>)>::~function ([pr105769.C:85:23] &D.85904); } } finally { [pr105769.C:85:23] std::function<vec<2, ab>(std::function<long unsigned int(long unsigned int)>)>::~function ([pr105769.C:85:23] &D.85869); } } finally { [pr105769.C:77:7] D.85344 = {CLOBBER(eol)}; } } finally { [pr105769.C:85:23] D.85869 = {CLOBBER(eol)}; } } finally { [pr105769.C:85:23] D.85904 = {CLOBBER(eol)}; } } finally { cov_jn = {CLOBBER(eol)}; bias = {CLOBBER(eol)}; } } D.85904 above is the return value (est2_t), D.85869 is the est argument, and bias variable is actually constructed even before this, all have 32 bytes in size. So, to me this looks like incorrect stack slot reuse.