Given the following code, the runtime generates a segfault on the same function when called through the procedure pointer instead of a direct function call: module m implicit none contains subroutine foo() integer :: a abstract interface subroutine ibar() end subroutine end interface procedure(ibar), pointer :: bar_ptr => bar_impl a = 0 call bar_impl() call bar_ptr() contains subroutine bar_impl() write (*,*) "foo" a = a + 1 end subroutine end subroutine end module program main use m call foo() end program it will generate the following output: $ ./segfault_minimal_rep foo foo Program received signal SIGSEGV: Segmentation fault - invalid memory reference. Backtrace for this error: #0 0x7f34795e7bbd in ??? #1 0x7f34795e6e03 in ??? #2 0x7f3478b02fdf in ??? #3 0x400788 in bar_impl at /users/tiziano/tmp/segfault_minimal_rep.f90:21 #4 0x4007c6 in __m_MOD_foo at /users/tiziano/tmp/segfault_minimal_rep.f90:16 #5 0x4007d1 in MAIN__ at /users/tiziano/tmp/segfault_minimal_rep.f90:30 #6 0x400808 in main at /users/tiziano/tmp/segfault_minimal_rep.f90:28 Segmentation fault (core dumped)
Confirmed with GCC 7.
The test works for me with 4.8.5. The change occurred between revisions r2370089 (2016-06-04, OK) and r237310 + one patch (2016-06-10, wrong code).
(In reply to Dominique d'Humieres from comment #2) > The test works for me with 4.8.5. The change occurred between revisions > r2370089 (2016-06-04, OK) and r237310 + one patch (2016-06-10, wrong code). Ok, then openSuSE must have some patches on their 4.8.5 which introduce the bug, since I get: tiziano@tcpc18 ~/tmp $ gfortran --version GNU Fortran (SUSE Linux) 4.8.5 Copyright (C) 2015 Free Software Foundation, Inc. GNU Fortran comes with NO WARRANTY, to the extent permitted by law. You may redistribute copies of GNU Fortran under the terms of the GNU General Public License. For more information about these matters, see the file named COPYING tiziano@tcpc18 ~/tmp $ gfortran -o segfault_minimal_rep segfault_minimal_rep.f90 -ggdb tiziano@tcpc18 ~/tmp $ ./segfault_minimal_rep foo foo Program received signal SIGSEGV: Segmentation fault - invalid memory reference. Backtrace for this error: #0 0x7f9bb46c7607 in ??? #1 0x7f9bb46c686d in ??? #2 0x7f9bb3be3fdf in ??? #3 0x4007bc in bar_impl at /users/tiziano/tmp/segfault_minimal_rep.f90:21 #4 0x4007f1 in __m_MOD_foo at /users/tiziano/tmp/segfault_minimal_rep.f90:16 #5 0x4007fc in MAIN__ at /users/tiziano/tmp/segfault_minimal_rep.f90:30 #6 0x400832 in main at /users/tiziano/tmp/segfault_minimal_rep.f90:28 Segmentation fault (core dumped)
(In reply to Dominique d'Humieres from comment #2) > The test works for me with 4.8.5. The change occurred between revisions > r2370089 (2016-06-04, OK) and r237310 + one patch (2016-06-10, wrong code). I see runtime segfaults with every gfortran version that I tried, starting from 4.6. 4.4 does not compile the example due to the proc-ptr init.
However I don't see any failures with this variant: program main call foo() contains subroutine foo() integer :: a abstract interface subroutine ibar() end subroutine end interface procedure(ibar), pointer :: bar_ptr => bar_impl a = 0 call bar_impl() call bar_ptr() end subroutine subroutine bar_impl() write (*,*) "foo" a = a + 1 end subroutine end program
(In reply to janus from comment #5) > However I don't see any failures with this variant: Sorry, I was a bit too quick in submitting this. It's really not a good example, since it's missing an "implicit none", so "bar_impl" supposedly gets its own private version of "a". The following variant fails again in the same way as the original test case: program main implicit none integer :: a call foo() contains subroutine foo() abstract interface subroutine ibar() end subroutine end interface procedure(ibar), pointer :: bar_ptr => bar_impl a = 0 call bar_impl() call bar_ptr() end subroutine subroutine bar_impl() write (*,*) "foo" a = a + 1 end subroutine end program I don't quite understand what's going on. Apparently the reference to the variable 'a' somehow goes wrong. But I don't see how the procedure pointer makes a difference here.
Created attachment 46016 [details] Assembly for test case Looking at the assembly of the test case in comment #6 (with -g -fverbose-asm only): .LBE2: # a.f90:29: a = a + 1 .loc 1 29 0 movl (%rbx), %eax # CHAIN.4_10(D)->a, _11 addl $1, %eax #, _12 movl %eax, (%rbx) # _12, CHAIN.4_10(D)->a When called through a procedure pointer, rbx no longer contains the address of a. Looking further up, we have movq %r10, %rbx # CHAIN.4, CHAIN.4 movq %r10, -552(%rbp) # CHAIN.4, .LBB2: so %r10 is clobbered. This happens in the call of _gfortran_st_write. Looking at the ABI, %r10 is not supposed to be preserved. Data point: This works on POWER9. This looks like a target bug to me.
Resetting priority to default, setting component to rtl-optimization and adding failing target.
(In reply to Dominique d'Humieres from comment #2) > The test works for me with 4.8.5. The change occurred between revisions > r2370089 (2016-06-04, OK) and r237310 + one patch (2016-06-10, wrong code). The only Fortran commits in that range are r237105 and r237108, neither of them appear to touch the area in question.
Bisecting this leads to /home/ig25/Gcc/Bisect-bin/./gcc/xgcc -B/home/ig25/Gcc/Bisect-bin/./gcc/ -xc -S -c /dev/null -fself-test ../../Bisect/gcc/input.c:1154: FAIL: ASSERT_STREQ (exp_filename, LOCATION_FILE (loc)) cc1: interner Compiler-Fehler: in fail, bei selftest.c:44 0x190e417 selftest::fail(char const*, int, char const*) ../../Bisect/gcc/selftest.c:44 0x191b6d9 assert_loceq ../../Bisect/gcc/input.c:1154 0x191bb1c test_builtins ../../Bisect/gcc/input.c:1213 0x191bc76 selftest::input_c_tests() ../../Bisect/gcc/input.c:1248 0x18b1e5c selftest::run_tests() ../../Bisect/gcc/selftest-run-tests.c:52 0xe8e510 toplev::run_self_tests() ../../Bisect/gcc/toplev.c:2048 Bitte senden Sie einen vollständigen Fehlerbericht auf Englisch ein; inclusive vorverarbeitetem Quellcode, wenn es dienlich ist. at r237159 :-( Trying Index: gcc/input.c =================================================================== --- gcc/input.c (Revision 237159) +++ gcc/input.c (Arbeitskopie) @@ -1151,7 +1151,7 @@ assert_loceq (const char *exp_filename, int exp_linenum, int exp_colnum, location_t loc) { - ASSERT_STREQ (exp_filename, LOCATION_FILE (loc)); + // ASSERT_STREQ (exp_filename, LOCATION_FILE (loc)); ASSERT_EQ (exp_linenum, LOCATION_LINE (loc)); ASSERT_EQ (exp_colnum, LOCATION_COLUMN (loc)); } to let this continue...
r237104 fails for me, testing r237008.
(In reply to Thomas Koenig from comment #11) > r237104 fails for me, testing r237008. r237007 also fails, as do earlier versions of the compiler. Not a regression then, but rather a design fault - seems like we need to do some magic to tell the middle end that we could access global variables (i.e. make sure that %r10 contains the right address).
The issue seems to be that the indirect call doesn't set up the static chain and this is because appearantly bar_ptr has static storage duration: foo () { static voidD.27 (*<T5c1>) (void) bar_ptrD.3873 = bar_implD.3867; integer(kind=4)D.8 D.3885; voidD.27 (*<T5c1>) (void) bar_ptr.2_1; integer(kind=4)D.8 _2; <bb 2> : _2 = 0; CHAIN.5_4(D)->aD.3880 = _2; bar_impl (); [static-chain: CHAIN.5_4(D)] bar_ptr.2_1 = bar_ptrD.3873; bar_ptr.2_1 (); return; I think this isn't supported: void foo() { int a; int bar() { return a; } static int (*bp)() = bar; bp(); } > ./cc1 -quiet t.c t.c: In function ‘foo’: t.c:9:24: error: initializer element is not constant 9 | static int (*bp)() = bar; | ^~~ I'm not sure how bar_ptr ends up statically allocated, that must be an error on the FE side - I'd have expected a SAVE to be needed? And the FE indeed accepts procedure(ibar), pointer, save :: bar_ptr => bar_impl but it should probably reject that. The IL it emits is the same, with or without the save. TREE_STATIC is set here: if (!sym->attr.use_assoc && (sym->attr.save != SAVE_NONE || sym->attr.data || (sym->value && sym->ns->proc_name->attr.is_main_program))) TREE_STATIC (decl) = 1; beacuse sym->attr.save == SAVE_IMPLICIT As said, the testcase is invalid if it needs SAVE since that prolongs lifetime of the static chain over the duration of the contained function.
Probably missed handling in add_init_expr_to_sym which needs to special case procedure-pointers to nested functions?
(In reply to Richard Biener from comment #13) > And the FE indeed accepts > > procedure(ibar), pointer, save :: bar_ptr => bar_impl > > but it should probably reject that. Indeed this is only valid since Fortran 2008: $ gfortran c0.f90 -std=f2003 c0.f90:12:53: 12 | procedure(ibar), pointer :: bar_ptr => bar_impl | 1 Error: Fortran 2008: non-NULL pointer initialization at (1)
can confirm, changing the reproducer to procedure(ibar), pointer :: bar_ptr => null() bar_ptr => bar_impl makes it generate valid code with the warning Warning: trampoline generated for nested function 'bar_impl' [-Wtrampolines]
(In reply to Tiziano Müller from comment #16) > can confirm, changing the reproducer to > > procedure(ibar), pointer :: bar_ptr => null() > bar_ptr => bar_impl > > makes it generate valid code Also this is only allowed since Fortran 2008: bar_ptr => bar_impl 1 Error: Fortran 2008: Internal procedure ‘bar_impl’ is invalid in procedure pointer assignment at (1)
(In reply to Richard Biener from comment #13) > As said, the testcase is invalid if it needs SAVE since that prolongs > lifetime of the static chain over the duration of the contained function. I agree. Looking into Fortran 2008, one finds: R1217 initial-proc-target is procedure-name and C1220(R1217) The procedure-name shall be the name of a nonelemental external or module procedure, or a specific intrinsic function listed in 13.6 and not marked with a bullet (•). Note that this does not list internal procedures.
I'll take care of fixing this.
(In reply to janus from comment #18) > C1220(R1217) The procedure-name shall be the name of a nonelemental external > or module procedure, or a specific intrinsic function listed in 13.6 and not > marked with a bullet (•). > > Note that this does not list internal procedures. In contrast to the corresponding restriction for procedure pointer assignments: C729 (R740) A procedure-name shall be the name of an internal, module, or dummy procedure, a procedure pointer, an external procedure that is accessed by use or host association and is referenced in the scoping unit as a procedure or that has the EXTERNAL attribute, or a specific intrinsic function listed in 13.6 and not marked with a bullet (•).
Another related test case with a dummy procedure in a proc-ptr init, which currently ICEs, but should be rejected: module m implicit none contains subroutine foo(dbar) interface subroutine dbar() end subroutine end interface procedure(dbar), pointer :: bar_ptr => dbar call bar_ptr() end subroutine end module program main use m implicit none call foo(bar_impl) contains subroutine bar_impl() integer :: a = 0 write (*,*) "foo" a = a + 1 end subroutine end program
Author: janus Date: Wed Mar 27 22:40:22 2019 New Revision: 269980 URL: https://gcc.gnu.org/viewcvs?rev=269980&root=gcc&view=rev Log: fix PR 85537 2019-03-27 Janus Weil <janus@gcc.gnu.org> PR fortran/85537 * expr.c (gfc_check_assign_symbol): Reject internal and dummy procedures in procedure pointer initialization. 2019-03-27 Janus Weil <janus@gcc.gnu.org> PR fortran/85537 * gfortran.dg/dummy_procedure_11.f90: Fix test case. * gfortran.dg/pointer_init_11.f90: New test case. Added: trunk/gcc/testsuite/gfortran.dg/pointer_init_11.f90 Modified: trunk/gcc/fortran/ChangeLog trunk/gcc/fortran/expr.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/gfortran.dg/dummy_procedure_11.f90
Fixed on trunk with r269980. Closing. Thanks for the report!