https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88511
Bug ID: 88511 Summary: passing allocatable character through two levels of procedure calls fails Product: gcc Version: 7.3.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: fortran Assignee: unassigned at gcc dot gnu.org Reporter: stephen at soliday dot com Target Milestone: --- Please see the thread that I started in Stack overflow. Several respondents have reproduced this problem in 8.2.1 and 9.0.0. In those threads there is reduced version of code that also reproduces the bug. I am experiencing an allocation failure when using allocatable character strings as optional arguments. The problem only occurs when I call through two levels of procedures. In my actual code ***call get_level1()*** (see below) represents a call to a list data structure and ***call get_level2()*** represents the list calling the same type of accessor function on one of its records. I have stripped down an example to the bare minimum that adequately reproduces the problem. In the code below when I call ***get_level2*** directly the expected character string is returned through the optional argument. When I call ***get_level1*** which in turn calls ***get_level2*** allocation of the optional dummy argument fails. Using gdb I find the allocation attempt to create a character*1635... when it gets back to the actual argument is obviously has an integer overflow because it thinks the allocation is character*-283635612... My actual code has many optional arguments not just one. As a simple example I added an optional integer argument. This time instead of a segmentation fault I get a null string. In the second example the integer argument works regardless of using the character argument. (I would expect this since no dynamic allocation is being performed) The integer's presence has no effect on the character. I have also tried changing the **intent** to (inout). This does not change the behavior, though I did not expect it to. [I believe that *intent(out)* causes the actual argument to deallocate first, and *intent(inout)* retains the actual argument's allocation state] call get_level1( NUM=n ) ! works call get_level1( NUM=n, TEXT=words ) ! fails call get_level1( TEXT=words ) ! fails my compile cmd is: gfortran -Wall -g -std=f2008ts stest1.f08 -o stest **Environment** Linux 4.15.0-42-generic #45-Ubuntu SMP x86_64 GNU/Linux GNU Fortran (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0 **Example with one optional argument** module stest1 implicit none character(:), allocatable :: data contains subroutine get_level2( TEXT ) implicit none character(:), optional, allocatable, intent(out) :: TEXT if ( PRESENT( TEXT ) ) then TEXT = 'Prefix: ' // data // ' :postfix' end if end subroutine get_level2 subroutine get_level1( TEXT ) implicit none character(:), optional, allocatable, intent(out) :: TEXT call get_level2( TEXT ) end subroutine get_level1 end module stest1 program main use stest1 implicit none character(:), allocatable :: words data = 'Hello Doctor' call get_level1( words ) write(*,100) words 100 format( 'words = [',A,']' ) end program main **Example with two optional arguments** module stest2 implicit none character(:), allocatable :: data integer :: count contains subroutine get_level2( TEXT, NUM ) implicit none character(:), optional, allocatable, intent(out) :: TEXT integer, optional, intent(out) :: NUM if ( PRESENT( TEXT ) ) then TEXT = 'Prefix: ' // data // ' :postfix' end if if ( PRESENT( NUM ) ) then NUM = count end if end subroutine get_level2 subroutine get_level1( TEXT, NUM ) implicit none character(:), optional, allocatable, intent(out) :: TEXT integer, optional, intent(out) :: NUM call get_level2( NUM=NUM, TEXT=TEXT ) end subroutine get_level1 end module stest2 program main use stest2 implicit none character(:), allocatable :: words integer :: n count = 42 data = 'Hello Doctor' call get_level1( TEXT=words ) write(*,100) words write(*,110) n 100 format( 'words = [',A,']' ) 110 format( 'N = [',I0,']' ) end program main