2

I am trying to have a generic subroutine event() and a procedure pointer to this generic subroutine, event_i. Then I would like to create any subroutine (like hello_wolrd in the following code) and point to this created subroutine. Can you help me to understand why the first code does not work while the second one does work? The error I get with the first version of the code is: Program received signal SIGSEGV: Segmentation fault - invalid memory reference. I would like to use the first version because then I can use inside the subroutine hello_world any variable defined in the main while in the second case I have to pass the variable to te subroutine and it cannot be defined anymore as a generic subroutine event(), which does not have input.

First version(not working)

program foo

  implicit none

  interface 
    subroutine event()
    end subroutine event
  end interface

   procedure(event), pointer :: event_i => Null()
   event_i => hello_world
   call event_i

contains

  subroutine hello_world()
    print *, 'hello_world'
  end subroutine

end program foo

Second version (working):

program foo

  implicit none

  interface 
    subroutine event()
    end subroutine event
    subroutine hello_world()
    end subroutine hello_world
  end interface

   procedure(event), pointer :: event_i => Null()
   event_i => hello_world
   call event_i

end program foo

subroutine hello_world()
  print *, 'hello_world'
end subroutine

I am using gfortran and the compiler version is

gfortran --version
GNU Fortran (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
fdv
  • 55
  • 8
  • The first version is not working (gives me segmentation fault), the second version works properly. I apologize for the unclear question. – fdv Jun 06 '18 at 11:31
  • Welcome on Stack Overflow. *Never* say *"it does not work"* or *"it isn't working"*, really *never*. Say what actually happens. Does it crash? Does it give wrong results? How does it crash?Any error message? Which exact message? Which exact wrong results and how should good results look like? – Vladimir F Героям слава Jun 06 '18 at 12:27
  • You are right, we have likely not been given the real code. And this is a problem, of course. @fdevita Please make a [mcve] that we can test ourselves and that really compiles. – Vladimir F Героям слава Jun 06 '18 at 17:25
  • I have fixed the error of the unterminated character in the print statement, added the error given by the first version and specified the complier version. – fdv Jun 06 '18 at 18:40
  • I have now tried your first program with gfortran versions older and newer than 5.4.0. In both cases it runs as expected. – francescalus Jun 07 '18 at 07:29
  • Does it means that is a compiler problem? Or there is a possibility to compile with the version 5.4.0 of gfortran shuch that it gives the proper execution in both version? – fdv Jun 07 '18 at 08:54
  • The program is valid and if it crashes when running something went wrong. It isn't an obvious compiler bug (unless affecting very specific versions) but there could be something else wrong with your particular installation or such. Can you try elsewhere or with a different compiler? – francescalus Jun 07 '18 at 10:33
  • I tried with a virtual machine running Ubuntu 18.04 with gfortran 7.3.0 and on a different computer running Debian with gfortran 6.3.0 and in both cases the code execute properly. Do you know if there is some compiler flag or option for gfortran version 5.3 that should be used in this case? – fdv Jun 07 '18 at 13:11
  • I wouldn't think there's a special flag for that version. Could you possibly reinstall the compiler and run-time? – francescalus Jun 07 '18 at 15:39
  • I was using ubuntu installed inside Windows and the version installed was 16.04 with gfortran 5.4.0. I have reinstall gfortran and nothing changed. Now I have installed also Ubuntu 18.04 inside Windows, and this distribution has gfortran 7.3.0 (the same I have already tested inside a virtual machine and was working) but the code does not execute properly, i.e. I get Segmentation fault when calling the procedure pointer. Interesting if I run the code in valgrind there is no error and I cann see on the screen the string 'hello world'. Is ubutnu on Windows broken? – fdv Jun 08 '18 at 21:53
  • @fdevita if it still is of any use, I just tried your first version on Ubuntu 18.04 inside Windows Subsystem for Linux, the first version fails with a segmentation fault both with gfortran (Ubuntu 7.3.0-27ubuntu1~18.04) and ifort (Version 19.0.1.144 Build 20181018). However, it runs just fine with ifort (Version 19.0.1.144 Build 20181018) on Windows proper. So seems like an issue on WSL then? – jbdv Jan 09 '19 at 08:24
  • This Q&A https://stackoverflow.com/a/50025069/3967096, about passing internal procedures as arguments (also a Fortran 2008 feature), indicates that WSL's non-executable stack is to blame. With this in mind, "First version" can be made to fail with a segmentation fault (or execute normally) on a Linux virtual machine by compiling using 'gfortran' with (or without) '-z noexecstack' flags. Thus, it seems like these two questions are related, and WSL specific. Perhaps an expert like @VladimirF could determine if this is indeed the case? – jbdv Jan 10 '19 at 11:16
  • @jbdv Absolutely, the passing is done using trampolines and the stack must be executable to execute the trampoline. The reason for that is the possibility to access the host scope. – Vladimir F Героям слава Jan 10 '19 at 12:15
  • 1
    So if one needs to use WSL, it seems one has to avoid this Fortran 2008 feature. According to https://groups.google.com/d/msg/comp.lang.fortran/6qUqEl8CIoc/EngOBhQaO5QJ Intel Fortran on Windows possibly uses a different mechanism. This explanation is for C nested functions in GCC but it remains valid for gfortran https://stackoverflow.com/a/33357450/721644 – Vladimir F Героям слава Jan 10 '19 at 12:19

1 Answers1

0

This is a slightly nontrivial modification, it works well with gfortran:

program foo

  implicit none

  abstract interface 
    subroutine event()
   end subroutine event
 end interface

  procedure(event), pointer :: event_i
  procedure(event), pointer :: event_j


 event_i => hello_world
 event_j => hello_world2

 call event_i
 call event_j


contains

 subroutine hello_world()
    print *, 'hello_world'
 end subroutine


 subroutine hello_world2()
   print *, 'HELLO_WORLD'
 end subroutine

end program foo
Michael
  • 42
  • 3