From 98bc7af7d4dce3fe9106ffff39c0b129b9466d40 Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Thu, 9 Jul 2020 15:07:30 -0700 Subject: [PATCH] mpi_f08: fix Fortran-8-byte-INTEGER vs. C-4-byte-int issue It is important to have the mpi_f08 Type(MPI_Status) be the same length (in bytes) as the mpif.h status (which is an array of MPI_STATUS_SIZE INTEGERs). The reason is because MPI_Status_ctof() basically does the following: MPI_Fint *f_status = ...; int *s = (int*) &c_status; for i=0..sizeof(MPI_Status)/sizeof(int) f_status[i] = c_status[i]; Meaning: the Fortran status needs to be able to hold as many INTEGERs are there are C int's that can fit in sizeof(MPI_Status) bytes. This is because a Fortran INTEGER may be larger than a C int (e.g., Fortran 8 bytes vs. C 4 bytes). Hence, the assignment on the Fortran side will take sizeof(INTEGER) bytes for each sizeof(int) bytes in the C MPI_Status. This commit pads out the mpi_f08 Type(MPI_Status) with enough INTEGERs to make it the same size as an array of MPI_TYPE_SIZE INTEGERs. Hence, MPI_Status_ctof() will work properly, regardless of whether it is assinging to an mpi_f08 Type(MPI_Status) or an mpif.h array of MPI_STATUS_SIZE INTEGERs. Thanks to @ahaichen for reporting the issue. Signed-off-by: Jeff Squyres --- config/ompi_setup_mpi_fortran.m4 | 26 +++++++++++++++---- .../fortran/use-mpi-f08/mod/mpi-f08-types.F90 | 14 ++++++++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/config/ompi_setup_mpi_fortran.m4 b/config/ompi_setup_mpi_fortran.m4 index 0880e9b7428..bfabf40d102 100644 --- a/config/ompi_setup_mpi_fortran.m4 +++ b/config/ompi_setup_mpi_fortran.m4 @@ -244,12 +244,28 @@ AC_DEFUN([OMPI_SETUP_MPI_FORTRAN],[ # How big should MPI_STATUS_SIZE be? (i.e., the size of # MPI_STATUS, expressed in units of Fortran INTEGERs). The C - # equivalent of MPI_Status contains 4 C ints and a size_t. + # MPI_Status struct contains 4 C ints and a size_t. OMPI_FORTRAN_STATUS_SIZE=0 - AC_MSG_CHECKING([for the value of MPI_STATUS_SIZE]) + + # Calculate how many C int's can fit in sizeof(MPI_Status). Yes, + # I do mean C ints -- not Fortran INTEGERS. The reason is because + # an mpif.h MPI_Status is an array of INTEGERS. But these + # sizeof(INTEGER) may be larger than sizeof(int). Hence, + # MPI_Status_ctof() basically does this: + # + # MPI_Fint *f_status = ...; + # int *s = (int*) &c_status; + # for i=0..sizeof(MPI_Status)/sizeof(int) + # f_status[i] = c_status[i]; + # + # Meaning: we have to have as many Fortran INTEGERs in the array + # as int's will fit in a C MPI_Status (vs. just having a Fortran + # array of INTEGERs that has enough bytes to hold a C MPI_Status). bytes=`expr 4 \* $ac_cv_sizeof_int + $ac_cv_sizeof_size_t` - num_integers=`expr $bytes / $ac_cv_sizeof_int` - sanity=`expr $num_integers \* $ac_cv_sizeof_int` + AC_MSG_NOTICE([C MPI_Status is $bytes bytes long]) + AC_MSG_CHECKING([for the value of MPI_STATUS_SIZE]) + num_ints=`expr $bytes / $ac_cv_sizeof_int` + sanity=`expr $num_ints \* $ac_cv_sizeof_int` AS_IF([test "$sanity" != "$bytes"], [AC_MSG_RESULT([unknown!]) AC_MSG_WARN([WARNING: Size of C int: $ac_cv_sizeof_int]) @@ -257,7 +273,7 @@ AC_DEFUN([OMPI_SETUP_MPI_FORTRAN],[ AC_MSG_WARN([WARNING: Size of Fortran INTEGER: $OMPI_SIZEOF_FORTRAN_INTEGER]) AC_MSG_WARN([Could not make this work out evenly...!]) AC_MSG_ERROR([Cannot continue])]) - OMPI_FORTRAN_STATUS_SIZE=$num_integers + OMPI_FORTRAN_STATUS_SIZE=$num_ints AC_MSG_RESULT([$OMPI_FORTRAN_STATUS_SIZE Fortran INTEGERs]) AC_SUBST(OMPI_FORTRAN_STATUS_SIZE) diff --git a/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-types.F90 b/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-types.F90 index ed3fc9388b4..a383f3bcf75 100644 --- a/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-types.F90 +++ b/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-types.F90 @@ -74,8 +74,18 @@ module mpi_f08_types integer :: MPI_SOURCE integer :: MPI_TAG integer :: MPI_ERROR - integer(C_INT) OMPI_PRIVATE :: c_cancelled - integer(C_SIZE_T) OMPI_PRIVATE :: c_count + ! The mpif.h interface uses MPI_STATUS_SIZE to know how long of + ! an array of INTEGERs is necessary to hold a C MPI_Status. + ! Effectively do the same thing here: pad out this datatype with + ! as many INTEGERs as there are C int's can fit in + ! sizeof(MPI_Status) bytes -- see MPI_Status_ctof() for an + ! explanation why. + ! + ! This padding makes this F08 Type(MPI_Status) be the same size + ! as the mpif.h status (i.e., an array of MPI_STATUS_SIZE + ! INTEGERs), which is critical for MPI_Status_ctof() to not + ! overwrite memory. + integer OMPI_PRIVATE :: internal(MPI_STATUS_SIZE - 3) end type MPI_Status !