Fortran accessing array it shouldn't

Hi all,

I’m having some trouble with some fortran code segfaulting when optimization is enabled in pgfortran.

Specifically, I’ve set up a 3D allocatable array. Under some circumstances, its allocated, and under these same circumstances, it is read later in the code. The circumstances which would prevent it from being allocated also prevent it from being accessed later in the code. However, when I compile with optimization (-O2) enabled, I am seeing segfaults resulting from accessing memory address 0x0. If I allocate this array even if the code shouldn’t access it, the program runs to completion. The problem also goes away if I compile with bounds checking (-Mbounds) enabled. In addition, the code compiles and runs without issue with gfortran, even when -O2 is used.

Below is a representative simplification. I’ve tried to make it as simple as possible. Note that in the actual code, I’m not doing things like empty ‘else’ statements. There is meaningful code within those regions. I removed as much code as I could while still making the problem repeatable.

It seems as though the compiler is attempting to perform the operations inside the conditionals even if the criteria is not met. Presumably this would be an optimization technique, and the results would only be used if the conditions were met?


I appreciate any help with this.

-Scot

module testmod
    real utest
    real, allocatable :: height(:,:),heightveg(:,:),can(:,:,:), z(:), zm(:)
    integer, allocatable :: cell(:,:,:)
    integer mx, my, mz, ktest,un, ustar1, ustar2, el
    integer i,j,k,kk,klow, dummy
end module

program main
    use testmod
    implicit none
         
    ktest = 0
    mx = 10
    my = 10
    mz = 10
    utest = 0.0
    un = 0
    ustar2 = 0
    dummy = 0
    
    allocate(height(mx,my), heightveg(mx,my))
    allocate(cell(mx,my,mz),zm(mz), z(mz))
    !allocate(can(mx,my,mz))
    height(:,:) = 0.0
    heightveg(:,:) = 0.0
    cell(:,:,:) = 0
    zm(:) = 0.0
    z(:) = 0.0

   j=1
   i=1
   !this whole loop should do nothing.  all the conditions for the 3 if blocks below should
   !not be met.  
	do k=2,mz
		!even though this if block should never be executed (cell is always = 0), removing it allows the code to run
		if(cell(i,j,k) .ge. 1)then                
			if(height(i,j) .gt. 0 .and. cell(i,j,k) .ne. 3)then                
			else          
			endif
		endif
		!because heightveg is zero everywhere, nothing inside this if statement should be
		!executed.  Even so, allocating the array 'can', which is only used within this if
		!statement, allows the program to run to completion
		if(heightveg(i,j) .ge. 1)then        	
			if(k .le. 5)then           
			else
				if(can(i,j,ktest) .ne. 0.0)then
					el=utest
				endif
			endif
		endif
		if(zm(k) .ge. 1)then   
			do kk=2,mz
				klow=kk
				if(max(height(i,j),heightveg(i,j))<z(kk))exit !replacing 'exit' with 'dummy = dummy + 1' allows the program to run to completion
			enddo
			if(k .eq. klow+1)then
				if(height(i,j) .ge. heightveg(i,j))then
				else			
					dummy = dummy + 1
				endif
			endif
			if(k .gt. klow)then	  
				if(heightveg(i,j) .gt. height(i,j))then		
					if(un .ge. 0)then
					else
					endif
			  	else !commenting this line out results in a working executable	 
				endif
			endif
		endif
	enddo      
	print *, dummy          
end program

Thanks Scot H for narrowing this down, we appreciate it. It looks to me that the compiler is hoisting the “can” array and not preserving the guards. Looks like it begin failing in the 13.9 release. I added a problem report (TPR#19915) and sent it on to engineering for further investigation.

Besides the work arounds you already have found, another would be to guard “can” with and “allocated” statement.

if(allocated(can) .and. can(i,j,ktest) .ne. 0.0)then
  • Mat

Thanks, Mat. I appreciate it.

Scot,

The 14.3 release corrects the problem reported as TPR 19915.

thanks,
dave