Fortran空数组边界检查:多编译器行为差异及合规性问询
Absoft技术支持确认,下文所述的
af95/af90行为属于非预期bug,Absoft开发团队将着手修复该问题,其余编译器的相关行为均符合规范。感谢@Vladimir F提供的解答、评论与建议。
问题背景
我原本认为Fortran对大小为0的空数组支持良好,但在使用Absoft Pro 21.0时遇到了涉及空数组的异常报错,而相同代码在gfortran、ifort、nagfor、pgfortran、sunf95、g95编译器上均可正常运行。
最小复现代码
! testempty.f90 !!!!!! 触发AF90/AF95报错的模块 !!!!!!!!!!!!!!!!!!!!!!!! module empty_mod implicit none private public :: foo contains subroutine foo(n) implicit none integer, intent(in) :: n integer :: a(0) integer :: b(n - 1) call bar(a) ! AF90/AF95运行这行没有问题 call bar(b) ! AF90/AF95运行这行报错 end subroutine foo subroutine bar(x) implicit none integer, intent(out) :: x(:) x = 1 ! 无论是否存在这行,调用bar(b)都会触发AF90/AF95报错 end subroutine bar end module empty_mod !!!!!! 模块结束 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!! 主程序 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! program testempty use empty_mod, only : foo implicit none call foo(2) ! AF90/AF95运行这行没有问题 call foo(1) ! AF90/AF95运行这行报错 write (*, *) '运行成功!' ! 运行到此处说明测试通过 end program testempty !!!!!! 主程序结束 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
复现步骤与报错信息
将上述代码保存为testempty.f90,执行以下命令:
$ af95 -no-pie -et -Rb -g -O0 -o atest testempty.f90 $ ./atest
在Ubuntu 20.04(linux 5.4.0-77-generic,x86_64)环境下得到如下报错:
./atest ? FORTRAN Runtime Error: ? Subscript 1 is out of range for dimension 1 for array ? B with bounds 1: ? File testempty.f90; Line 19 ? atest, run-time exception on Mon Sep 13 14:08:41 2021 ? Program counter: 000000001004324B ? Signal SIGABRT, Abort ? Traceback follows OBJECT PC ROUTINE LINE SOURCE libpthread.so.0 000000001004324B raise N/A N/A atest 00000000004141F3 __abs_f90rerr N/A N/A atest 000000000041CA81 _BOUNDS_ERROR N/A N/A atest 00000000004097B4 __FOO.in.EMPTY_MO N/A N/A atest 000000000040993A MAIN__ 40 testempty.f90 atest 000000000042A209 main N/A N/A libc.so.6 000000000FD0C0B3 __libc_start_main N/A N/A atest 000000000040956E _start N/A N/A
可见af95会在call bar(b)处触发报错,af90运行结果一致。使用gfortran、ifort、nagfor、pgfortran、sunf95、g95测试相同代码,即便显式开启边界检查也可正常运行,测试用Makefile如下:
# 该Makefile用于测试不同编译器对空数组的支持情况 # # af95: Absoft 64-bit Pro Fortran 21.0.0 # gfortran: GNU Fortran (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 # ifort: ifort (IFORT) 2021.2.0 20210228 # nagfor: NAG Fortran Compiler Release 7.0(Yurakucho) Build 7036 # pgfortran: pgfortran (aka nvfortran) 21.3-0 LLVM 64-bit x86-64 # sunf95: Oracle Developer Studio 12.6 # g95: G95 (GCC 4.0.3 (g95 0.94!) Jan 17 2013) # # 测试环境:Ubuntu 20.04,Linux 5.4.0-77-generic x86_64 .PHONY: test clean test: make -s gtest make -s itest make -s ntest make -s ptest make -s stest make -s 9test make -s atest gtest: FC = gfortran -Wall -Wextra -fcheck=all itest: FC = ifort -warn all -check all ntest: FC = nagfor -C ptest: FC = pgfortran -C -Mbounds stest: FC = sunf95 -w3 -xcheck=%all -C 9test: FC = g95 -Wall -Wextra -fbounds-check atest: FC = af95 -no-pie -et -Rb %test: testempty.f90 $(FC) -g -O0 -o $@ $< ./$@ clean: rm -f *.o *.mod *.dbg *test
问题解答
1. af95/af90的上述行为是否符合Fortran标准要求?
不符合。Fortran从95标准开始就明确支持大小为0的空数组,自动数组长度为0属于合法场景,边界检查不应该对长度为0的数组抛出下标越界错误。所有其他主流编译器的一致表现也侧面印证了这一点,Absoft官方也已经确认该行为属于编译器bug,会在后续版本修复。
2. 代码是否存在违反Fortran 2003、2008、2018版标准的内容?
不存在。你的代码完全符合各版本Fortran标准的要求:自动数组的长度声明逻辑合法,向假设形参数组传递空数组的操作符合标准,空数组的赋值操作x=1也符合Fortran对零大小数组的赋值规则(赋值操作不会执行,也不会产生越界)。
3. Fortran代码中使用空数组是否存在风险?
- 标准层面完全没有风险:空数组是Fortran标准明确支持的特性,所有符合标准的编译器都应该正确处理空数组的声明、传递、赋值、运算等操作,是处理可变规模数据时非常常用的合法特性。
- 实际使用中唯一的风险来自少数老旧或维护较差的编译器存在的未修复bug,比如这次遇到的Absoft的问题。如果你的代码需要兼容这类存在bug的编译器,可以在涉及空数组传递的位置加简单的长度判断,数组长度为0时跳过对应的子程序调用即可规避问题。
内容的提问来源于stack exchange,提问作者Nuno

