Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28895 Discussions

interesting bug when contains subroutines used

coolman
Beginner
1,827 Views

Despite the debug window show errer in my last post https://community.intel.com/t5/Intel-Fortran-Compiler/ifort-debug-bug/td-p/1520195/jump-to/first-unread-message.

the contains subroutines exhibits very strange bugs.  see the following simple program which has two contains subroutines, resize and resize2, the two subs are identical except the name.

    module mydata
    
    type tlist    
    integer*4,allocatable::items(:)
character (len=:), allocatable :: name
contains
final:: free_tlist
    endtype 
    
     type(tlist),dimension(:),allocatable,target:: a,b
   
contains
  impure elemental subroutine free_tlist(object)
type (tlist), intent(inout) ::  object
if(allocated(object%items))deallocate(object%items)
endsubroutine
   
    endmodule 
    
    program main
    
    use mydata
    integer::i
    
    
    call resize2()
    call resize2()
    
    contains
     subroutine resize()
    integer::newsize,osize,i
     type(tlist),dimension(:),allocatable:: c
   
    osize=0
    if(allocated(b))osize=size(b)
    newsize=osize+1
    allocate(c(newsize))
    do i=1,osize
    c(i)=b(i)
    enddo
    call MOVE_ALLOC(c,b)
    allocate(b(newsize)%items(20))
    do i=1,20
        b(newsize)%items(i)=i+20
    enddo
    endsubroutine
    
     subroutine resize2() !same as sub resize
    integer::newsize,osize,i
     type(tlist),dimension(:),allocatable:: c
   
    osize=0
    if(allocated(b))osize=size(b)
    newsize=osize+1
    allocate(c(newsize))
    do i=1,osize
    c(i)=b(i)
    enddo
    call MOVE_ALLOC(c,b)
    allocate(b(newsize)%items(20))
    do i=1,20
        b(newsize)%items(i)=i+20
    enddo
    endsubroutine
       
   end program main

The program will run in failure in the second call to resize2( windows 10, VS  2022 community, IFORT or IFX). However if you remove the contains sub resize which is never called, all are OK.

This bug is very difficult to debug. can anyone explain it? thanks.
0 Kudos
12 Replies
TobiasK
Moderator
1,802 Views

Hi @coolman 

can you please use the 'code' formatting when pasting code?

0 Kudos
Steve_Lionel
Honored Contributor III
1,784 Views
0 Kudos
JohnNichols
Valued Contributor III
1,781 Views
  module mydata
    
    type tlist    
    integer*4,allocatable::items(:)
character (len=:), allocatable :: name
contains
final:: free_tlist
    endtype 
    
     type(tlist),dimension(:),allocatable,target:: a,b
   
contains
  impure elemental subroutine free_tlist(object)
type (tlist), intent(inout) ::  object
if(allocated(object%items))deallocate(object%items)
endsubroutine
   
    endmodule 
    
    program main
    
    use mydata
    integer::i
    
    
    call resize2()
    call resize2()
    
    contains
     subroutine resize()
    integer::newsize,osize,i
     type(tlist),dimension(:),allocatable:: c
   
    osize=0
    if(allocated(b))osize=size(b)
    newsize=osize+1
    allocate(c(newsize))
    do i=1,osize
    c(i)=b(i)
    enddo
    call MOVE_ALLOC(c,b)
    allocate(b(newsize)%items(20))
    do i=1,20
        b(newsize)%items(i)=i+20
    enddo
    endsubroutine
    
     subroutine resize2() !same as sub resize
    integer::newsize,osize,i
     type(tlist),dimension(:),allocatable:: c
   
    osize=0
    if(allocated(b))osize=size(b)
    newsize=osize+1
    allocate(c(newsize))
    do i=1,osize
    c(i)=b(i)
    enddo
    call MOVE_ALLOC(c,b)
    allocate(b(newsize)%items(20))
    do i=1,20
        b(newsize)%items(i)=i+20
    enddo
    endsubroutine
       
   end program main

Prefer that you insert as shown so we can read it - and try and stay in the same lane. 

0 Kudos
Barbara_P_Intel
Employee
1,757 Views

Thanks, @Steve_Lionel , I deleted the other thread!

 

0 Kudos
Barbara_P_Intel
Employee
1,756 Views

What version of Visual Studio are you using? There are known issues with v17.7.x. We are working on a solution.

 

0 Kudos
uha
Novice
1,705 Views

I see the same issue (at least very similar) in my production code after upgrading from 2023.1 to 2023.2. VS version is 17.6.2.

The error message is the same (153 - "allocatable array or pointer is not allocated"). My code also implements a dynamically growing array. That array contains a custom type, which in turn contains another custom type (abstract) which is not being used/allocated in all cases. I tested with a case where this object is not being used and ran into the deallocation error. Then I removed that unused object from the type declaration and the problem disappeared! It does not make a difference if the growing array is using allocatables and move_alloc or pointers and simple (de)allocate.

I tried to reproduce this scenario in a smaller example, but didn´t succeed in that, so I cannot put my finger on exactly what makes the difference.

One thing I noticed is that when using pointer arrays and I right away deallocate the freshly allocated array again there is no error if I use the same pointer used for allocation, but the error does occur if I use another pointer assigned to the array, like so (much simplified):

type(myType), pointer :: tmp(:), arr(:)
allocate(tmp(5))
arr => tmp
deallocate(arr) ! fails
deallocate(tmp) ! works


Can you confirm the issue?
 

0 Kudos
andrew_4619
Honored Contributor III
1,691 Views

 

module mydata
    implicit none (type, external)
    type tlist
        integer, allocatable::items(:)
    endtype 
    type(tlist),dimension(:),allocatable,target:: a,b
endmodule
    
program main
    use mydata
    implicit none (type, external)
    call resize2()  ! first call ok
    call resize2()  ! runtime crash in second call , if they are both resize1() it runs
    ! if we delete the uncalled resize1 it runs also
    ! finally I commented out the substance of resize1 and it still fails
    contains
    subroutine resize1()
      !  integer::newsize,osize,i
      !  type(tlist),dimension(:),allocatable:: c
      !  osize=0
      !  if(allocated(b))osize=size(b)
      !  newsize=osize+1
      !  allocate(c(newsize))
      !  do i=1,osize
      !      c(i) = b(i)
      !  enddo
      !  call MOVE_ALLOC(c,b)
      !  allocate(b(newsize)%items(20))
      !  do i=1,20
      !      b(newsize)%items(i)=i+20
      !  enddo
    endsubroutine
    subroutine resize2() !same as sub resize
        integer::newsize,osize,i
        type(tlist),dimension(:),allocatable:: c
        osize=0
        if(allocated(b))osize=size(b)
        newsize=osize+1
        allocate(c(1))
        do i=1,osize
            c(i) = b(i)
        enddo
        call MOVE_ALLOC(c,b)     ! fails on this line
        allocate(b(newsize)%items(20))
        do i=1,20
            b(newsize)%items(i)=i+20
        enddo
    endsubroutine
end program main

Out of interest I cut down the reproducer a bit. It seems the presence of a preceding contains routine is important, as even with zero code in the first subroutine the problem is encountered and if the running code is the first subroutine it works. It also works if we remove the module and put the declarations in main. I am guessing some namespace house keeping is at error.

 

0 Kudos
uha
Novice
1,663 Views

Andrew, isn´t it that in your version the second call to resize2 fails with array out of bounds in the second allocate statement (not deallocation triggered by move_alloc) because you only allocate c to size 1 instead of "newsize"?

To me it seems like only the first routine containing a move_alloc (or deallocate) statement for a given custom type will work as expected. If I just comment out this line of resize() (the first function):

call MOVE_ALLOC(c,b)

then I can call resize2() any number of times without problems. I also tried with my production code using pointer arrays, and it seems when I delegate all deallocate(myObjectArray) to a module function and not call any deallocate on that type in any other function I can get around the problem.

0 Kudos
andrew_4619
Honored Contributor III
1,650 Views

I don't think so,  move_alloc(from, to) and from as allocated the size is not important at that point I think.

The bigger point is that the code runs or doesn't run based on any number of changes elsewhere in the code that should have no effect.

0 Kudos
uha
Novice
1,643 Views

Andrew, my point was that in your code line 39 it is

 

allocate(c(1))

 

while in the original code it is

 

allocate(c(newsize))

 

so after move_alloc the size of b is always 1, and in the second call to the function when newsize is 2 and you access b(newsize) in line 44 then index 2 is out of bounds. This is at least how your version fails for me. If you really do get the original error (153 - "allocatable array or pointer is not allocated") when calling move_alloc I´d be curious how it can fail in different ways for you and me.

0 Kudos
andrew_4619
Honored Contributor III
1,636 Views

OK C was allocated newsize when I made the initial tests, I tried a few different things and posted the wrong version. But in all the tests that failed the debug exception was always on the move_alloc. If you look at the case below, it fails on the move alloc but if I comment out the never used mov_alloc in resize1 is does not fail. This is just indicative of the code incorrectly managing memory (corruption) so unrelated changes change the behaviour.  

 

module mydata
    implicit none (type, external)
    type tlist
        integer, allocatable::items(:)
    endtype 
    type(tlist),dimension(:),allocatable,target:: a,b
endmodule
    
program main
    use mydata
    implicit none (type, external)
    call resize2()  ! first call ok
    call resize2()  ! runtime crash in second call , if they are both resize1() it runs
    ! if we delete the uncalled resize1 it runs also
    ! finally I commented out the substance of resize1 and it still fails
    contains
    subroutine resize1()
        integer::newsize,osize,i
        type(tlist),dimension(:),allocatable:: c
        call MOVE_ALLOC(c,b)  ! comment the never called line to 'fix' the code
    endsubroutine
    subroutine resize2() !originally the same as sub resize1
        integer::newsize,osize,i
        type(tlist),dimension(:),allocatable:: c
        osize=0
        if(allocated(b))osize=size(b)
        newsize=osize+1
        allocate(c(newsize))
        do i=1,osize
            c(i) = b(i)
        enddo
        call MOVE_ALLOC(c,b)     ! fails on this line
        allocate(b(newsize)%items(20))
        do i=1,20
            b(newsize)%items(i)=i+20
        enddo
    endsubroutine
end program main
0 Kudos
Ron_Green
Moderator
1,624 Views

I can reproduce the runtime crash with the 2023.2.0 version of ifx.

ifx -g -traceback -O0 old.f90
$ ./a.out
forrtl: severe (153): allocatable array or pointer is not allocated
Image              PC                Routine            Line        Source             
a.out              0000000000405DEF  resize2                    32  old.f90
a.out              0000000000405211  main                       13  old.f90
a.out              00000000004051CD  Unknown               Unknown  Unknown
libc.so.6          00007F11A0566B4A  Unknown               Unknown  Unknown
libc.so.6          00007F11A0566C0B  __libc_start_main     Unknown  Unknown
a.out              00000000004050E5  Unknown               Unknown  Unknown

but I tested a pre-build of the upcoming 2024.0.0 and it's not present

ifx -g -traceback -O0 -what -V repro.f90
 Intel(R) Fortran 24.0-1238.1
GNU ld version 2.39-9.fc38

$ ./a.out
$ 

I'm not sure what fixed this, but it's fixed and in the code for 2024.0.0. We're wrapping up last minute edits to the 2024.0.0 version.  Due out in Q4 2023.

0 Kudos
Reply