pgf77 memory allocation segmentation fault error

I am trying to use an array that has been dynamically allocated, and although the compiler has no problem, during run time I get a segmentation fault error. I realize this is usually the error one receives when one is trying to access memory outside of what has been allocated, but I am not doing this. Can you find fault with the technique I am using here?

Here is my makefile:

PROGRAM = nautreverb
FC = /opt/pgi/linux86-64/6.1/bin/pgf77
FSRCS = nautreverb.f
FOBJS = $(FSRCS:.f=.o)
INCLUDE = -I. -L.
FFLAGS = -g

$(PROGRAM): $(FOBJS)
     $(FC) $(FFLAGS) -o $@ $(INCLUDE) $(FOBJS)

clean:
     rm *.o

And here is my code:

program nautreverb
implicit none
real*8 disttp(*)
integer nn, nxtot, nytot, nx, ny
integer*4 malloc
integer*4 dsize

pointer( disttp_ptr,disttp)

dsize = 8
nxtot = 10
nytot = 10

disttp_ptr = malloc(dsize*1001*1001)

nn=0
do 100 nx=1,nxtot
     do 200 ny=1,nytot
          nn=nn+1
          write(*,*) nx,ny,nn
          disttp(nn) = 1
          write(*,*) disttp(nn)
200 continue
100 continue
end

The output is

1 1 1
Segmentation fault

Note that if I change the allocated arraysize to be dsize101101, the code works fine with no seg fault. This is also the case if I simply declare the array to be 1001*1001 instead of allocating. What is the problem?

Thanks,
Jennifer

malloc is not a fortran function. You probably pick up the C library malloc, but on 64-bit systems a pointer size is 8 bytes and you are trying to stuff it into a 4 byte integer. You should also probably declare disttp to be real*8 disttp(1). Just make sure you don’t turn on -Mbounds.

If you can use fortran 95, I would suggest using it and take advantage of allocatable variables.

Actually, malloc is an f77 feature according to page 270 of the PGI Fortran Reference Manual at http://www.pgroup.com/doc/pgifortref.pdf

I would love to use fortran 95, but this is legacy code I am working with, and I’m forced to solve the problem at hand.

Any other answers?

Hi Jennifer,

The problem is that you have malloc declared as “integer4". This is correct for 32-bit pointers but for 64-bit pointers you need to declare this "integer8”. Note that malloc only accepts an integer*4 argument so can not be used with very large arrays.

Hope this helps,
Mat

Maybe I should have been clearer in that it is not standard fortran 77. It’s an extension provided by the compiler. And it states that many of the implementations use the C library. In any case, the rest of my post describes the issue you are having with using 4 byte pointers when 64-bit Linux uses 8 byte pointers.

As far as fortran 95, the standard was written in such a way that standard fortran 77 is valid fortran 95. So, you could change a file extension and be able to use fortran 95.

Taking both of your advice, I changed the code so that malloc was declared integer*8, but there was no change in the output. When you say malloc cannot be used with very large arrays, what does “very large” mean? Is there another mistake in my program?

You should repost the corrected code. Did you also change the other integer variables that were meant to be pointers?

By very large arrays, he means anything that overflows an integer*4. This is probably a question for Mat, but if the malloc is just the system malloc, it takes an argument of size_t which should be 8 bytes on Linux 64. Maybe they wrap that through fortran and that’s why is says integer. In any event, here is a corrected version of your code which valgrind indicates no memory problems. Note that I snipped your write statement outputs to save space in the post.

[chulbert@fourier ~]$ pgf77 -Mcray=pointer test.f
[chulbert@fourier ~]$ valgrind --memcheck:leak-check=yes ./a.out
[chulbert@fourier ~]$
[chulbert@fourier ~]$ cat test.f
program nautreverb
implicit none
real8 disttp()
integer nn, nxtot, nytot, nx, ny
integer8 malloc,disttp_ptr
integer
4 dsize

pointer( disttp_ptr,disttp)

dsize = 8
nxtot = 10
nytot = 10

disttp_ptr = malloc(dsize10011001)

nn=0
do 100 nx=1,nxtot
do 200 ny=1,nytot
nn=nn+1
write(,) nx,ny,nn
disttp(nn) = 1
write(,) disttp(nn)
200 continue
100 continue

call free(disttp_ptr)
end
[chulbert@fourier ~]$ pgf77 -Mcray=pointer test.f
[chulbert@fourier ~]$ valgrind --memcheck:leak-check=yes ./a.out
==6982== Memcheck, a memory error detector.
==6982== Copyright © 2002-2006, and GNU GPL’d, by Julian Seward et al.
==6982== Using LibVEX rev 1618, a library for dynamic binary translation.
==6982== Copyright © 2004-2006, and GNU GPL’d, by OpenWorks LLP.
==6982== Using valgrind-3.3.0.SVN, a dynamic binary instrumentation framework.
==6982== Copyright © 2000-2006, and GNU GPL’d, by Julian Seward et al.
==6982== For more details, rerun with: -v
==6982==


**** snip all the write statements *****


==6982==
==6982== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 10 from 5)
==6982== malloc/free: in use at exit: 8,000 bytes in 1 blocks.
==6982== malloc/free: 2 allocs, 1 frees, 8,024,008 bytes allocated.
==6982== For counts of detected errors, rerun with: -v
==6982== searching for pointers to 1 not-freed blocks.
==6982== checked 176,616 bytes.
==6982==
==6982== LEAK SUMMARY:
==6982== definitely lost: 0 bytes in 0 blocks.
==6982== possibly lost: 0 bytes in 0 blocks.
==6982== still reachable: 8,000 bytes in 1 blocks.
==6982== suppressed: 0 bytes in 0 blocks.
==6982== Reachable blocks (those to which a pointer was found) are not shown.
==6982== To see them, rerun with: --show-reachable=yes

Hi Jennifer,

By “very large”, I mean arrays over 2Gb since the PGI F77 malloc only accepts an integer*4. Malloc and other “3f” functions are not standard Fortran but rather a common extension. Most are simply Fortran wrappers to C library functions (as Chris correctly points out). A complete list of 3f functions can be found in the PGI Fortran Reference Guide.

As for you code, it works for me with 6.1, 6,2 and the upcoming 7.0 release once I change malloc’s definition.

% cat ~/tmp/test.f
      program nautreverb
      implicit none
      real*8 disttp(*)
      integer nn, nxtot, nytot, nx, ny
      integer*8 malloc
      integer*4 dsize

      pointer( disttp_ptr,disttp)

      dsize = 8
      nxtot = 10
      nytot = 10

      disttp_ptr = malloc(dsize*1001*1001)

      nn=0
      do 100 nx=1,nxtot
         do 200 ny=1,nytot
            nn=nn+1
            write(*,*) nx,ny,nn
            disttp(nn) = 1
            write(*,*) disttp(nn)
 200     continue
 100  continue
      end
% pgf77 -V6.1-1 -g -Mcray=pointer ~/tmp/test.f
% a.out
            1           1           1
    1.000000000000000
            1           2           2
    1.000000000000000

... continues to completion
  • Mat

I copied exactly your code, and now it works like a charm. Thanks to both of you for your help.