1
1

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 <jsquyres@cisco.com>
Этот коммит содержится в:
Jeff Squyres 2020-07-09 15:07:30 -07:00
родитель ad81839dd5
Коммит 98bc7af7d4
2 изменённых файлов: 33 добавлений и 7 удалений

Просмотреть файл

@ -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)

Просмотреть файл

@ -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
!