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