Усечение строки отложенной длины при передаче в качестве необязательного - PullRequest
2 голосов
/ 14 февраля 2020

Я передаю необязательные строки с отложенной длиной (character(len=:), allocatable, optional) между подпрограммами и получаю неожиданное поведение в G CC.

Вот мой минимальный пример, где я передаю необязательную строку через процедуру интерфейса к подпрограмме, которая устанавливает его:

$ cat main.f90 
module deepest_call_m
   implicit none
contains
subroutine deepest_call(str)
   character(len=:), allocatable, intent(OUT), optional :: str

   if (present(str)) str = '12345'
   write(*,*) 'at bot of deepest_call, str is "'//trim(str)//'"'
end subroutine deepest_call
end module deepest_call_m

module interface_call_m
   implicit none
contains
subroutine interface_call(str)
   use deepest_call_m, only : deepest_call
   character(len=:), allocatable, intent(OUT), optional :: str

   call deepest_call(str=str)
   write(*,*) 'at bot of interface_call, str is "'//trim(str)//'"'
end subroutine interface_call
end module interface_call_m

program main
   use interface_call_m, only : interface_call
   implicit none

   character(len=:), allocatable :: str

   call interface_call(str=str)
   write(*,*) 'at bot of main, str is "'//trim(str)//'"'
end program main

(Обратите внимание, что для простоты я не заключаю операторы записи в if(present) и if(allocated), хотя это было бы необходимо для реальной реализации. )

В Intel 16.0 и 2019_U4, а также в PGI 15.10 эта процедура дает ожидаемый результат: str устанавливается в deepest_call и остается неизменным до interface_call и main:

$ ifort --version
ifort (IFORT) 16.0.0 20150815
Copyright (C) 1985-2015 Intel Corporation.  All rights reserved.

$ ifort main.f90 && ./a.out 
 at bot of deepest_call, str is "12345"
 at bot of interface_call, str is "12345"
 at bot of main, str is "12345"

Однако с gfortran 4.8.5:

$ gfortran --version
GNU Fortran (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
Copyright (C) 2015 Free Software Foundation, Inc.

GNU Fortran comes with NO WARRANTY, to the extent permitted by law.
You may redistribute copies of GNU Fortran
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING

$ gfortran main.f90 && ./a.out 
 at bot of deepest_call, str is "12345"
 at bot of interface_call, str is ""
 at bot of main, str is ""

Строка была обрезана при возврате из deepest_call в interface_call. В gfortran 7.3.0 и 8.2.0 код завершает работу во время выполнения, если не предоставлены параметры времени компиляции:

[chaud106@epyc-login-1-0 Testing]$ gfortran --version && gfortran main.f90 && ./a.out
GNU Fortran (GCC) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 at bot of deepest_call, str is "12345"

Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

Backtrace for this error:
#0  0x2af39a82733f in ???
#1  0x400c68 in ???
#2  0x400d9c in ???
#3  0x400f0e in ???
#4  0x2af39a813494 in ???
#5  0x400878 in ???
#6  0xffffffffffffffff in ???
Segmentation fault

Однако добавление проверки во время компиляции восстанавливает предыдущее поведение усечения:

$ gfortran --version
GNU Fortran (GCC) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gfortran -g -fbacktrace -Wall -Wextra -std=f2008 -fcheck=all -Og main.f90 && ./a.out
 at bot of deepest_call, str is "12345"
 at bot of interface_call, str is ""
 at bot of main, str is ""

Для меня это очень похоже на ошибку компилятора, так что, возможно, мне просто нужно опубликовать сообщение на bugzilla. Но сначала я хотел бы получить некоторые отзывы, а именно:

  1. Соответствует ли мой тестовый пример стандарту? Меня особенно интересует аргумент str=str для deepest_call. Я часто использую эту структуру, чтобы передать аргумент как необязательный, если и только если он необязателен в данной области, но я не мог легко найти это в стандарте, и я не уверен, действительно ли он действителен. Прохождение только str, похоже, показало то же поведение.

  2. Есть ли какие-нибудь простые обходные пути? Учитывая, что эта проблема затрагивает широкий спектр версий (4.8.5–8.2.0), просто избежать их невозможно.

  3. Кто-нибудь знает об этом поведении для других версий gfortran, или другие компиляторы? У меня есть только легкий доступ к G CC, Intel и PGI.

1 Ответ

1 голос
/ 14 февраля 2020

Ваш код соответствует стандарту.

Необязательный фиктивный аргумент может быть фактическим фиктивным аргументом в последующем вызове без ключевого слова, и независимо от того, присутствует он или нет. (Конечно, он может отсутствовать только в том случае, если следующий фиктивный аргумент является необязательным.) То есть:

call  interface_call(str)

точно так же, как

call  interface_call(str=str)

Что касается (неоптимальные) обходные пути (я вижу, что это не работает с gfortran 9.1.0, но работает с gfortran 10.0.0 20190625), вы можете рассмотреть аргументы как не отложенные по длине. В конце концов, вы используете trim везде, поэтому конечный пробел будет разбит на кусочки.


Ваш код - это всего лишь одно небольшое изменение по сравнению с несоответствием: операторы записи не защищены проверка присутствия для дополнительного манекена. Если в цепочке вызовов отсутствует необязательная пустышка, программа будет недействительной.

...