0

I'm not familiar with Fortran, but I had to use my advisor's old code but it didn't work, and I could track down it to a minimal working example.

hello.f is following:

  implicit none
  character*200 rec
  integer var,idum
  real*4 rdum
  call xparse('-t0',1,1,'required',rec,idum,rdum)
  print *, rec
  read(rec,'(i6)')   var
  print *, var
  END

And extra.f is following:

c------------------------------------------------------------------
      subroutine xparse(cc,nth,ifo,req,carg,iarg,rarg)
c------------------------------------------------------------------
      character*(*) cc,req,carg
      character*256 rec
c
      iver=0
      lcc=len(cc)
      na=iargc()
      ith=0
      do 100 ia=1,na
      call getarg(ia,rec)
      if(rec(1:15).eq.'-xparse_verbose') iver=1
      lrec=ilen(rec,256)
      if(lrec.eq.lcc) then
      if(rec(1:lcc).eq.cc(1:lcc)) then
      if(iver.eq.1)write(0,'(a,a)')'xparse ,parsing:',rec(1:lcc)
c
      if(nth.le.0) then
      iarg=1
      return
      endif
c
      ith=ith+1
      if(ith.eq.nth) then
c
      if(ia.eq.na) then
      write(0,*)'parse error :  missing value for ',cc
      endif
      call getarg(ia+1,rec)
      lrec=ilen(rec,256)
      if(iver.eq.1)write(0,'(a,a)')'xparse, string:',rec(1:lrec)
      if(ifo.eq.1) then
      if(iver.eq.1)write(0,'(a,a)')'xparse, character:',rec(1:lrec)
      carg=rec
      else if(ifo.eq.2) then
      s=gets(rec)
      if(s.ge.0.0)iarg=s+0.1
      if(s.lt.0.0)iarg=s-0.1
      if(iver.eq.1)write(0,*)'xparse, integer:',iarg
      else if(ifo.eq.3) then
      rarg=gets(rec)
      if(iver.eq.1)write(0,*)'xparse, real:',rarg
      endif
      return
c
      endif
      endif
      endif
100   continue
c
      if(req(1:8).eq.'required') then
      write(0,*)'parse error :  cant find required arg:  ',cc
      stop
      endif
      end
c------------------------------------------
      real function gets(cc)
c------------------------------------------
c
c  decodes integer or floating f format
c  from character string
c
      character*(*) cc
      nn=len(cc)
c
      gets=0.0
      fak=1.
      ief=0
      l1=0
      l2=0
      do 200 i=1,nn
      if(cc(i:i).eq.'e'.or.cc(i:i).eq.'E')ief=i
      if(cc(i:i).eq.'d'.or.cc(i:i).eq.'D')ief=i
      if(l1.eq.0.and.cc(i:i).ne.' ')l1=i
      if(cc(i:i).ne.' ')l2=i
      if(cc(i:i).eq.' '.and.l2.gt.0) goto 201
200   continue
201   continue
      nn=l2
      if(ief.gt.0) then
      lex=l2-ief
      iex=-9999999
      if(lex.eq.1)read(cc(ief+1:l2),'(i1)',err=900) iex
      if(lex.eq.2)read(cc(ief+1:l2),'(i2)',err=900) iex
      if(lex.eq.3)read(cc(ief+1:l2),'(i3)',err=900) iex
      if(lex.eq.4)read(cc(ief+1:l2),'(i4)',err=900) iex
      if(lex.eq.5)read(cc(ief+1:l2),'(i5)',err=900) iex
      if(iex.gt.-999999) then
      if(iex.lt.0)fak=1./( 10.**(-iex) )
      if(iex.gt.0)fak=10.**iex
      else
      write(0,*)'gets: cannot read ',cc
      endif
      nn=ief-1
      endif
c
      sig=1.
      ss=0.
      tt=1.
      ip=0
      do 100 l=1,nn
      if(cc(l:l).ne.' ') then
      if(cc(l:l).eq.'.') then
      ip=1
      else if(cc(l:l).eq.'-') then
      sig=-1.
      else
c      read(cc(l:l),'(i1)',err=900) ii
      ii=ichar(cc(l:l))-48
      if(ii.lt.0.or.ii.gt.9) goto 109
      if(ip.eq.0) then
      ss=10.*ss+float(ii)
      else
      tt=0.1*tt
      ss=ss+tt*float(ii)
      endif
      endif
      endif
100   continue
109   continue
      gets=ss*sig*fak
      return
900   continue
      write(0,*)' gets: error reading formatted integer:'
      write(0,*)nn
      write(0,'(a,a,a)')'$',cc,'$'
      return
      end
c-------------------------------------
      integer function ilen(c,m)
c-------------------------------------
      character*80 c
      k=1
      do 100 i=1,m
      if(c(i:i).ne.' '.and.c(i:i).ne.char(0))k=i
100   continue
      ilen=k
      jlen=k
      return
      end

If I do

gfortran hello.f extra.f

./a.out -t0 10800

I get the error

10800

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

Backtrace for this error:
#0  0x10a01735c
#1  0x10a0166f3
#2  0x7fff7376cb5c
#3  0x10a15b340
#4  0x10a15bd2d
#5  0x10a15978f
#6  0x10a00c917
#7  0x10a00c9e5
Segmentation fault: 11

That read function(?) is the one frequently used in the code to read user input (like Python's sys.argv) but I can't see why it fails.

I'm using GNU Fortran (Homebrew GCC 9.3.0_1) 9.3.0, MacOS Mojave 10.14.6.

7
  • You may have changed the meaning when reducing your code. With that read statement your are reading from unit 10800 (a preconnected file). Perhaps you meant to read from the string "10800" but that's not what this code does. Please explain what you think the program should be doing. Commented May 8, 2020 at 1:45
  • @francescalus I know. I just wanted to show that error is still there even if the code is not the same. Originally the code calls a subroutine that has a function(?) which get 'rec' from the user input, but that subroutine is pretty long so I just shortened to show error. Commented May 8, 2020 at 1:48
  • What do you think this program is doing? Its behaviour is not defined by the Fortran standard (relying on the preconnection of an external file to unit 10800), so for us to be able to address your question here we need to know what you want to happen. As you are using gfortran, do you have a file called fort.10800 in your working directory, for example? Commented May 8, 2020 at 1:57
  • Wait, sorry I'm really noob for Fortran. So rec should be file pointer, not variable? Give me a minute and I'll edit the post to reflect it's original use. Commented May 8, 2020 at 2:19
  • Yes, that program is trying to read from a file. If that file doesn't exist then a runtime failure is to be expected. Commented May 8, 2020 at 2:23

1 Answer 1

0

There is a bug in the function ilen. Consider

      character*80 c
      k=1
      do 100 i=1,m
      if(c(i:i).ne.' '.and.c(i:i).ne.char(0))k=i
100   continue

The variable (dummy argument) c is declared to be of length 80, but in the loop the substring c(81:81) is surely attempted to be accessed if m is bigger than 80 (which it is when called in the program). This is incorrect.

You can index c up to position 80 with

      do 100 i=1,80
      ...

or up to its length:

      do 100 i=1,len(c)
      ...

Alternatively, you can make c have length 256 or not (necessarily) 80:

c Have the length of the dummy argument assumed
      character*(*) c

or

c Have the length given by the argument m
      character*(m) c

There are also the modern ways to write character declarations such as

      character(len=*) c

and

      character(len=m) c
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer. However, even if I fix ilen to i=1,len(c), same error persists.
You can compile with the "usual options" -fcheck=all -O0 -g -fbacktrace and get more detail on where the new error comes about.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.