Повреждение указателя символов в Intel Fortran при включении OpenMP

Я работаю над совместимостью Intel Fortran для довольно большого кода (модель прогнозирования погоды). На Intel Fortran (и только на Intel Fortran) некоторые символьные данные, кажется, скремблируются и указывают на них символьные указатели. Символы, которые у меня заканчиваются, содержат только 0 и 9. Строка символов c просто имеет "00:00:00:16 (whitespace padding....)" как его содержание.

Я был в состоянии воспроизвести проблему, чтобы появиться всякий раз, когда я включаю (мертвый) код OpenMP и использую -fopenmp флаг компилятора. Я немного растерялся из-за того, что здесь происходит. Можете ли вы обнаружить какие-либо программные ошибки в следующем минимальном воспроизводителе? Если нет, я думаю, я сообщу об ошибке компилятора.

репродуктор

minimal.f90

module foo
    implicit none

    type pointer_character
    character, pointer :: c
    end type
    type(pointer_character), allocatable :: ptr_c(:)
    integer(4) :: idx_c

    contains

    subroutine grpbcast_set_c(c)
        implicit none
        character(*), intent(in), target :: c
        integer(4) :: cloc

        allocate(ptr_c( 256 ))
        idx_c = 0

        do cloc = 1, len(c)
            idx_c = idx_c + 1
            ptr_c( idx_c )%c => c( cloc:cloc )
        end do

        print *, "testprint-2", c
        print *, "testprint-3.1", ptr_c( 1 )%c
        print *, "testprint-3.2", ptr_c( 2 )%c
        print *, "testprint-3.3", ptr_c( 3 )%c
        print *, "testprint-3.4", ptr_c( 11 )%c

    end subroutine

    ! The following subroutine is never called, but if we include it in the module foo, it will lead to the data corruption documented in
    ! http://stackru.com/questions/42359258/intel-fortran-substring-access-with-convert-big-endian
    ! If the subroutine is commented it will work
    !
    ! In other words:
    ! if we comment this subroutine out, the output will be
    ! =====================================================
    ! testprint-2
    ! 00:00:00:16



    ! testprint-3.10
    ! testprint-3.20
    ! testprint-3.3:
    ! testprint-3.46
    ! =====================================================
    ! However if we include it, the output will be
    ! testprint-2
    ! 00:00:00:16



    ! testprint-3.10
    ! testprint-3.20
    ! testprint-3.30
    ! testprint-3.40
    ! =====================================================
    !
    ! tested with: ifort 17.0.1 20161005
    subroutine scatter_one_record()
     implicit none
     integer(4) :: k

!$OMP PARALLEL DO
    do k = 1, 5
    end do
!$OMP END PARALLEL DO
    end subroutine

end module foo

program main
    use foo, only: grpbcast_set_c
    implicit none

    character(len=256), target:: run_period
    run_period = "00:00:00:16"

    call grpbcast_set_c(run_period)
end program

Makefile

.PHONY: all

all: minimal

minimal.o: minimal.f90
    ifort -fopenmp -c minimal.f90 -o minimal.o

minimal: minimal.o
    ifort -fopenmp -o minimal -L./ minimal.o

версия ifort

> ifort --version
ifort (IFORT) 17.0.1 20161005

компиляции и запуска

make
./minimal

..

..

Предыдущий анализ, только здесь, чтобы понять цепочку комментариев к этому вопросу

Цикл в вопросе

subroutine grpbcast_set_c(c)
 use nrtype, only : rp => rp
 implicit none
 character(*), intent(in), target :: c
 integer(4) :: cloc

 do cloc = 1, len(c)
  idx_c = idx_c + 1
  if (idx_c > max_ptr_gbcast) stop 9
  ptr_c( idx_c )%c => c( cloc:cloc )
 end do
end subroutine

Спецификация ptr_c в модуле

type pointer_character
   character, pointer :: c
end type

type(pointer_character), private, allocatable, save :: ptr_c(:)

Данные, как видно в отладчике (TotalView)

Данные во время выполнения

Команда компилятора

> mpif90 -O0 -no-ipo -g -convert big_endian -fopenmp -r8 -DUSE_MPI -I/usr/apps.sp3/mpi/openmpi/1.6.5/i2013.1.046/include -I/usr/apps.sp3/mpi/openmpi/1.6.5/i2013.1.046/lib -I [NUSDAS13_PATH]/src -I [NETCDF_PATH]/include -DUSE_MPI -c mpi_comm.f90 -o mpi_comm.o

> mpif90 --version
ifort (IFORT) 14.0.2 20140120
Copyright (C) 1985-2014 Intel Corporation.  All rights reserved.

Обновить

Я только что попробовал то же самое с новейшей версией компилятора Intel:

> mpif90 --version
> ifort (IFORT) 17.0.1 20161005

Результат все еще неправильный, но другой! На этот раз я обнуляю всех персонажей.

Новейшая Intel

Новейший Intel - начало массива

Обновление 2

Я пытался воспроизвести проблему с минимальным воспроизводителем (см. Ниже), пока не повезло, то есть ошибка не появляется при запуске этого пути. Однако интересно одно: TotalView показывает первый адрес массива немного по-другому:

с указателем рабочего массива

Я думаю, это должно быть проблема с вводом cдаже если он правильно отображается в отладчике в том месте, где grpcast_set_c введен

module foo
    implicit none

    type pointer_character
        character, pointer :: c
    end type
    type(pointer_character), allocatable, save :: ptr_c(:)
    integer(4), save :: idx_c
contains

    subroutine parmread_bcast_a( mt, aout, chktag )
        implicit none
        integer(4), intent(in):: mt
        character(*), intent(out):: aout
        character(*), intent(in):: chktag

        call filetool_cardread_a( mt, aout, chktag )
        write(6,'("* ",a28," = ", a)') chktag, trim(aout)

        call set_ptr_c(aout)
        return
    end subroutine parmread_bcast_a

    subroutine filetool_cardread_a( imt, aout, chktag )
        implicit none
        integer(4), intent(in):: imt
        character(*), intent(out):: aout
        character(*), intent(in), optional:: chktag

        character(len=256):: tag
        character(len=256):: val
        character(len=256):: buff
        integer(4):: idxeql
        integer(4) :: is_debug = 0

        cardread: do
            read( imt, "(a)" ) buff
            if( buff(1:1) /= "*" ) then
                idxeql = index(buff, "=")
                tag = adjustl(buff(:idxeql-1))
                if (is_debug == 1) then
                write(6,*) 'buff', trim(buff)
                endif
                if ( present( chktag ) ) then
                if ( trim(chktag) /= trim(tag) ) then
                    write(6,*)"WARNING !!! the record is for ", trim(tag), &
                    & ", while you specified ", trim(chktag)
                    cycle cardread
                endif
                endif
                val = adjustl(buff(idxeql+1:))
                aout = val
                return
            end if
        end do cardread
    end subroutine filetool_cardread_a

    subroutine set_ptr_c(c)
        implicit none
        character(*), intent(in), target :: c
        integer(4) :: cloc

        do cloc = 1, len(c)
            idx_c = idx_c + 1
            if (idx_c > 10000) stop 9
            ptr_c( idx_c )%c => c( cloc:cloc )
        end do
    end subroutine
end module

program main
    use foo, only: ptr_c, idx_c, parmread_bcast_a
    implicit none

    character(len=256), save:: run_period

    allocate(ptr_c( 10000 ))
    idx_c = 0

    open( 100, file='sample.conf', form='formatted')
    call parmread_bcast_a(100, run_period, "run_period")

    print *, "run period", run_period

    print *, ptr_c( 1 )%c
    print *, ptr_c( 2 )%c
    print *, ptr_c( 3 )%c
    print *, ptr_c( 11 )%c
end program

sample.conf

  run_period               =    00:00:00:16

1 ответ

Решение

В качестве обходного пути работает разделение кода OpenMP от такого рода инициализации структуры данных на несколько модулей (даже в одном и том же файле). В вышеуказанном случае:

module foo1
    implicit none

    type pointer_character
    character, pointer :: c
    end type
    type(pointer_character), allocatable :: ptr_c(:)
    integer(4) :: idx_c

    contains
    subroutine grpbcast_set_c(c)
        implicit none
        character(*), intent(in), target :: c
        integer(4) :: cloc

        allocate(ptr_c( 256 ))
        idx_c = 0

        do cloc = 1, len(c)
            idx_c = idx_c + 1
            ptr_c( idx_c )%c => c( cloc:cloc )
        end do

        print *, "testprint-2", c
        print *, "testprint-3.1", ptr_c( 1 )%c
        print *, "testprint-3.2", ptr_c( 2 )%c
        print *, "testprint-3.3", ptr_c( 3 )%c
        print *, "testprint-3.4", ptr_c( 11 )%c

    end subroutine
end module    

module foo2
    implicit none

    contains
    subroutine scatter_one_record()
     implicit none
     integer(4) :: k

!$OMP PARALLEL DO
    do k = 1, 5
    end do
!$OMP END PARALLEL DO
    end subroutine
end module

program main
    use foo1, only: grpbcast_set_c
    implicit none

    character(len=256), target:: run_period
    run_period = "00:00:00:16"

    call grpbcast_set_c(run_period)
end program
Другие вопросы по тегам