Dave Buchan
Dave Buchan

Reputation: 23

Segmentation fault with assumed size array

I'm having a seg fault when executing the following code:

program test

call sub ('dave')

end program test


subroutine sub (arr)

character (*) :: arr
character (20) :: upperc

arr = upperc (arr)

return

end subroutine sub


character (*) function upperc (str)

integer i, l
character (*) :: str

upperc = str
l = len (str)
do i = 1, l
  icode = ichar (str (i:i))
  if ((icode >= ichar ('a')).and.(icode <= ichar ('z'))) then
    upperc (i:i) = char (ichar ('A') + icode - ichar('a'))
  end if
enddo

return

end function upperc

The seg fault occurs on the following line:

arr = upperc (arr)

Here's the compilation and GDB runtime output:

[dave@VM-15 ~]$ gfortran -g -Wall test.f90
[dave@VM-15 ~]$ gdb
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) file ./a.out
Reading symbols from /home/dave/a.out...done.
(gdb) run
Starting program: /home/dave/./a.out

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff70f1fa3 in __memmove_ssse3_back () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-    2.17-106.el7_2.8.x86_64 libgcc-4.8.5-4.el7.x86_64 libgfortran-4.8.5-4.el7.x86_64 libquadmath-4.8.5-4.el7.x86_64
(gdb) backtrace
#0  0x00007ffff70f1fa3 in __memmove_ssse3_back () from /lib64/libc.so.6
#1  0x000000000040078c in sub (arr='dave', _arr=4) at test.f90:13
#2  0x00000000004008e9 in test () at test.f90:3
#3  0x000000000040091f in main (argc=1, argv=0x7fffffffe7b3) at test.f90:5
#4  0x00007ffff6fc3b15 in __libc_start_main () from /lib64/libc.so.6
#5  0x0000000000400669 in _start ()
(gdb) q
A debugging session is active.

    Inferior 1 [process 20941] will be killed.
[dave@VM-15 ~]$

I get a funny feeling it has something to do with the fact that I'm passing a literal, but maybe not.

In an attempt to fix it, I tried the following instead, and it works fine:

program test2

character(20) text

text = 'dave'

call sub (text)

end program test2


subroutine sub (arr)

character (*) :: arr
character (20) :: upperc

arr = upperc (arr)

return

end subroutine sub


character (*) function upperc (str)

integer i, l
character (*) :: str

upperc = str
l = len (str)
do i = 1, l
  icode = ichar (str (i:i))
  if ((icode >= ichar ('a')).and.(icode <= ichar ('z'))) then
    upperc (i:i) = char (ichar ('A') + icode - ichar('a'))
  end if
enddo

return

end function upperc

Can anyone tell me what is going on?

Upvotes: 2

Views: 650

Answers (1)

Markus Dutschke
Markus Dutschke

Reputation: 10606

The problem is that the subroutine sub writes into the variable text from program test2. When you do not give a variable as an agrument to sub, but just 'dave' like in the first program test, Fortran intends to overwrite an area in memory, which is not assigned as a variable. This leads to the segmentation fault.

Below you see your working example. Note two changes:

  1. the length of the character text was set to 6 instead of 20. This was done to demonstrate that thing still fit together, as the subroutine sub takes an argument of arbitrary length.

  2. We write 2 times the value of variable text to the console and it was changed by call sub(text)

program test3

character(6) text

text = 'dave'

write(*,*) text

call sub (text)

write(*,*) text

end program test3


subroutine sub (arr)

character (*) :: arr
character (20) :: upperc

arr = upperc (arr)

return

end subroutine sub


character (*) function upperc (str)

integer i, l
character (*) :: str

upperc = str
l = len (str)
do i = 1, l
  icode = ichar (str (i:i))
  if ((icode >= ichar ('a')).and.(icode <= ichar ('z'))) then
    upperc (i:i) = char (ichar ('A') + icode - ichar('a'))
  end if
enddo

return

end function upperc 

Upvotes: 2

Related Questions