I just invested in a new Mac with an M1 chip. I’m getting a segmentation fault for this code:
module mylib
implicit none
abstract interface
subroutine fcn_p
end subroutine
end interface
contains
subroutine tester()
real(8) :: a
a = 20.d0
call dumb(bla)
contains
subroutine bla()
print*,a
end subroutine
end subroutine
subroutine dumb(fcn)
procedure(fcn_p) :: fcn
call fcn()
end subroutine
end module
program main
use mylib
implicit none
call tester()
end program
compile with
gfortran test.f90 -O3
result is…
zsh: segmentation fault ./a.out
My installation of gfortran
GNU Fortran (Homebrew GCC 11.2.0_3) 11.2.0
I do not get a segmentation fault when I use no optimization (no -O3). Also no segmentation fault every on intel mac or on ubuntu virtual machine.
No traceback? I could be missing something, but looks like a compiler issue to me so far. If you have gdb it might be interesting to try to run it there; sticking in a few prints might help isolate the problem but I still do not see a problem on your side.
module mylib
implicit none
abstract interface
subroutine fcn_p
end subroutine
end interface
contains
subroutine tester()
real(8) :: a
a = 20.d0
print*,'hi1'
call dumb(bla)
contains
subroutine bla()
print*,'hi3'
print*,a
end subroutine
end subroutine
subroutine dumb(fcn)
procedure(fcn_p) :: fcn
print*,'hi2'
call fcn()
end subroutine
end module
program main
use mylib
implicit none
call tester()
end program
gives me
hi1
hi2
zsh: segmentation fault ./a.out
The issue seems to be with the variable a. When I comment out print*,a within subroutine bla, then there is no segmentation fault. I do not see any mac m1 binaries of gdb. So i can’t try that very quickly.
The segfault could be due to the internal function bla(). Converting it to a regular procedure may resolve the segfault.
I do not know much about M1, but the segfault can be reproduced in Linux by marking the output binary as not requiring an executable stack (internal functions require an executable stack with gfortran).
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Try this alternative code to see if this is indeed the source of error,
module mylib
implicit none
integer, parameter :: RK = kind(1.d0)
#if !EXECSTACK_ENABLED
real(RK) :: a
#endif
abstract interface
subroutine fcn_p
end subroutine
end interface
contains
#if EXECSTACK_ENABLED
subroutine tester()
real(RK) :: a
a = 20.d0
call dumb(bla)
contains
subroutine bla()
print*,a
end subroutine
end subroutine
#else
subroutine tester()
a = 20.d0
call dumb(bla)
end subroutine
subroutine bla()
print*,a
end subroutine
#endif
subroutine dumb(fcn)
procedure(fcn_p) :: fcn
call fcn()
end subroutine
end module
program main
use mylib
implicit none
call tester()
end program
Cannot find anything saying it is illegal, but that is pushing things a bit, where the procedure passed in is contained, which certainly makes the scope of A a bit convoluted. It would change the code quite a bit, but wondering if it goes away if you move the declaration of A (the REAL statement) before the first CONTAINS. If you put an IMPLICIT NONE in the BLA routine it does not (in my opinion, incorrectly) say A is not defined, does it? That would definitely be a bug but might give a hint about what it is doing wrong. Have to admit the logic here is not anything I have done but I see no reason it is not standard. Cannot say passing in the procedure to call and having it in a contained routine and using a variable it gets access to by being a contained procedure is a first for me.
The only (?) Fortran feature not yet working in gfortran for M1 are procedure pointers to internal subprograms: https://twitter.com/fxcoudert/status/1315356308703506432. I believe it is indeed related to an executable stack not being allowed. Note, that gcc for M1 is experimental and not yet officially included in gcc.