Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Possible bug in passing assumed-rank arguments

Peil__Oleg
Beginner
718 Views
Originally, the issue was posted as a problem with Intel MPI: https://software.intel.com/en-us/forums/intel-clusters-and-hpc-technology/topic/852075 However, it has turned out to be related to the Fortran compiler itself. An unexpected segfault occurs when one tries to pass a 2D array subsection of a multi-dimensional array to a subroutine defined with an assumed rank dummy argument `type(*), dimension(..)` [defined in Fortran 2015 standard]. These types of arguments are heavily used in `mpi_f08` interface of the MPI 3.x standard. The following minimal example should demonstrate this behavior. The program runs and prints the correct values but then crashes with a segfault when it tries to leave subroutine `test_assumed_rank_arg()`. The program is compiled from two files, `test_assumed_rank.f90` and `c_fun.c`, as follows:
icc -c c_fun.c
ifort -o test_assumed_rank test_assumed_rank.f90 c_fun.o
Source files:
module test_assumed_rank_mod
   implicit none
   integer, parameter :: dp = kind(1.0d0)

   type :: Container
      real(kind=dp), allocatable :: arr(:, :, :)
   end type

   interface
      subroutine c_fun(arr, n) bind(C, name='c_fun')
         use iso_c_binding, only: c_ptr, c_int
         type(c_ptr), value :: arr
         integer(c_int), value :: n
      end subroutine
   end interface
contains
   subroutine fun(arr, n)
      use iso_c_binding, only: c_ptr, c_int, c_loc

      !> arr will be treated as an array of real(dp)
      type(*), intent(inout) :: arr(..)
      integer, intent(in) :: n

      type(c_ptr) :: p_arr
      integer(c_int) :: c_n
      p_arr = c_loc(arr)
      c_n = n

      call c_fun(p_arr, c_n)
   end subroutine fun

   subroutine test_assumed_rank_arg()
      type(Container) :: cont

      allocate(cont % arr(1, 1, 1))

      cont % arr(1, 1, 1) = 42.0_dp

      print *, " before `c_fun`: ", cont % arr(1, 1, 1)

!---> works      call fun(cont % arr(:, 1, 1), 1)
      call fun(cont % arr(:, :, 1), 1)

      print *, " after `c_fun`: ", cont % arr(1, 1, 1)
   end subroutine test_assumed_rank_arg
end module test_assumed_rank_mod

program test_assumed_rank
   use test_assumed_rank_mod
   call test_assumed_rank_arg()
end program

The C-function is defined as follows (in c_fun.c):

#include <stdio.h>

void c_fun(void *p, int n) {
   // Assume that `p` points to an array of double
   double *p_arr = (double *)p;

   printf("n = %d\n", n);
   printf("`p` contains: %lf\n", *p_arr);
}

I reiterate relevant details from the original post:

  • The subroutine must be in a module
  • The array must be at least 3-dimensional, allocatable, and be contained in a derived type object
  • The subsection must be at least 2-dimensional. As noted in the comment in the source above, 1D subsection does not cause any issue.

Compiler/library versions:

Intel(R) Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 19.1.1.217 Build 20200306

OS: CentOS Linux release 7.6.1810 (Core)

Kernel: 3.10.0-957.10.1.el7.x86_64

0 Kudos
7 Replies
FortranFan
Honored Contributor II
718 Views

Thanks for sharing.

  • Assume you've reported this to Intel Support (https://supporttickets.intel.com/servicecenter?lang=en-US) and they've opened an incident for this issue?
  • By the way, it's Fortran 2018 standard, not 2015.
  • And technically, you need TARGET attribute with your assumed-rank and assumed-type dummy argument 'arr' in your procedure 'fun' for the code to conform i.e., C_LOC procedure requires its parameter 'X" to have either the TARGET or POINTER attribute.
  • If you change the dummy argument in 'fun' to be of type REAL(dp) i.e., not have it as assumed-type, your trouble case also works.  This might be of help to Intel Fortran team diagnose and resolve the issue.

 

 

0 Kudos
Peil__Oleg
Beginner
718 Views

Thanks for response.

FortranFan wrote:
I have made an attempt to do that but all the formatting seems to have gone south (and, unfortunately, there is no preview of what is to be sent). Anyway, I've left the links to the forum threads. This should help to get the source listings.
FortranFan wrote:
  • By the way, it's Fortran 2018 standard, not 2015.
Yes, you are right. The issue has probably more to do with TS 29113.
FortranFan wrote:
  • And technically, you need TARGET attribute with your assumed-rank and assumed-type dummy argument 'arr' in your procedure 'fun' for the code to conform i.e., C_LOC procedure requires its parameter 'X" to have either the TARGET or POINTER attribute.
  • If you change the dummy argument in 'fun' to be of type REAL(dp) i.e., not have it as assumed-type, your trouble case also works.  This might be of help to Intel Fortran team diagnose and resolve the issue.

 

 

Noted. I essentially just copied the subroutine interface as defined in `mpi_f08`, as the issue first started to pester me in the context of an MPI application.
0 Kudos
Steve_Lionel
Honored Contributor III
718 Views

You don't need the C routine to see this problem - remove it and the call to c_fun (though the C routine at least lets you see that the array was passed correctly.)

The error occurs when test_assumed_rank tries to deallocate local allocatable variable cont. I'm guessing that the code that set up the call to fun somehow corrupted the data that would later be passed to for_deallocate_all_nocheck.

0 Kudos
Peil__Oleg
Beginner
718 Views
Steve Lionel (Ret.) (Blackbelt) wrote:

You don't need the C routine to see this problem - remove it and the call to c_fun (though the C routine at least lets you see that the array was passed correctly.)

The error occurs when test_assumed_rank tries to deallocate local allocatable variable cont. I'm guessing that the code that set up the call to fun somehow corrupted the data that would later be passed to for_deallocate_all_nocheck.

Thanks for this comment. Then, the issue seems to be unrelated to TS29113 and CFI, as I suspected at first.
0 Kudos
jimdempseyatthecove
Honored Contributor III
718 Views

type(*), intent(inout) :: arr(..)

passes the address of the array descriptor and not that which is the address of the first array element.

Jim Dempsey

0 Kudos
Steve_Lionel
Honored Contributor III
718 Views

jimdempseyatthecove (Blackbelt) wrote:

type(*), intent(inout) :: arr(..)

passes the address of the array descriptor and not that which is the address of the first array element.

Jim Dempsey

Yes, as it has to. But the compiler knows to look in the descriptor for the base address - and it does.

0 Kudos
Steve_Lionel
Honored Contributor III
718 Views

The problem is related to TS29113, as that's where TYPE(*) and DIMENSION(..) come from. But it is unrelated to C descriptors.

0 Kudos
Reply