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

Issue with move_alloc intrinsic

Oleg_Butakov
Novice
570 Views

Hello everyone!

 

I have encountered the following problem with the move_alloc intrinsic:

I am expecting the following code

program strange

    type :: Something
        integer :: data
    end type Something

    class(Something), allocatable :: a, b

    a = Something(100)
    call move_alloc(from=a, to=b)
    a = Something(200)

    print *, a%data, b%data

end program strange

to output '200 100' (which it does with gfortran/pgfortran), but both ifort and ifx crash with the message:

forrtl: severe (122): invalid attempt to assign into a pointer that is not associated
Image              PC                Routine            Line        Source             
a.out              00000000004085E6  Unknown               Unknown  Unknown
a.out              0000000000404B2A  Unknown               Unknown  Unknown
a.out              0000000000404862  Unknown               Unknown  Unknown
libc.so.6          00007F65C86ACFD0  Unknown               Unknown  Unknown
libc.so.6          00007F65C86AD07D  __libc_start_main     Unknown  Unknown
a.out              0000000000404765  Unknown               Unknown  Unknown

 I am running Ubuntu 22.10 with ifort version 2021.4.0 and ifx version 2021.4.0 Beta.

Replacement of 'class' with 'type' does not cause the crash.

 

Regards, Oleg

0 Kudos
1 Solution
Barbara_P_Intel
Moderator
378 Views

Thanks for the nice reproducer and for the triage tip about changing Class to Type.

I filed a bug report, CMPLRIL0-34514, on your behalf.

In case you are interested, the failure occurs at the

a = Something(200)

statement. We added an ALLOCATED() check after the MOVE_ALLOC. A is not allocated. A should be allocated automatically since it is on the LHS (left hand side) and it is allocatable.

I'll let you know when it is fixed.


View solution in original post

7 Replies
andrew_4619
Honored Contributor II
540 Views

Well that seems like a bug but your usage case seems very strange, in effect you are allocating B as the same size and bounds as A  and afterwards A will be deallocated and B will be allocated but uninitialized. The intended usage of MOVE_ALLOC is to make and existing data structure bigger with only one data copy being needed. If you use STAT or  ERRMSG what do you get?

Oleg_Butakov
Novice
522 Views

Hi Andrew!

 

'move_alloc' finishes without any error (stat==0).

Crash happens on assignment to the allocatable variable, which was 'from' argument of 'move_alloc' (line 11 of the listing above).

Looks like the internal state of that variable was not completely reset to the deallocated state.

 

My intended usage of 'move_alloc' is the following (pipeline of stream):

type, abstract :: tOutputStream
  ! ...
end type :: tOutputStream

type, extends(tOutputStream) :: tUnitOutputStream
  ! ...
end type tUnitOutputStream

type, extends(tOutputStream) :: tBase64OutputStream
  class(tOutputStream), allocatable, private :: InnerStream
  ! ...
end type tBase64OutputStream

interface tBase64OutputStream
  module procedure MakeBase64OutputStream
end interface tBase64OutputStream

function MakeBase64OutputStream(innerStream, ...) result(stream)
  class(tOutputStream), intent(inout), allocatable :: innerStream
  ! ...
  type(tBase64OutputStream) :: stream

  call move_alloc(from=innerStream, to=stream%InnerStream)
  ! ...

end function MakeBase64OutputStream

type, extends(tOutputStream) :: tZLibOutputStream
  class(tOutputStream), allocatable, private :: InnerStream
  ! ...
end type tZLibOutputStream

interface tZLibOutputStream
  module procedure MakeZLibOutputStream
end interface tZLibOutputStream

function MakeZLibOutputStream(innerStream, ...) result(stream)
  class(tOutputStream), intent(inout), allocatable :: innerStream
  ! ...
  type(tZLibOutputStream) :: stream

  call move_alloc(from=innerStream, to=stream%InnerStream)
  ! ...  

end function MakeZLibOutputStream

! ...

stream = tUnitOutputStream(unit)
if (binary) then
  stream = tBase64OutputStream(stream)
  if (compressed) then
    stream = tZLibOutputStream(stream)
  end if
end if

Of course, the code above can be rewritten with pointers, but in my opinion, with allocatables it looks much cleaner (resembles the 'std::unique_ptr' from C++). Please correct me if I am doing something wrong/not in a Fortran-ish way. Thanks!

 

Regards, Oleg

andrew_4619
Honored Contributor II
510 Views
stream%InnerStream = innerStream ! stream%InnerStream will be allocated AND get a copy of InnerStream data
deallocate( InnerStream ) 

Is this what you are trying to do? By default in Fortran on whole array assignment the LHS is automatically allocated or reallocated.

 

Oleg_Butakov
Novice
505 Views

Technically, yes. But I am assuming that with 'move_alloc' the innerStream is transferred to stream%InnerStream without copying.

Then, e.g., on line:

stream = tBase64OutputStream(stream)

I assume that the 'stream' is moved inside the newly create instance of 'tBase64OutputStream' (and the 'stream' variable is in the 'deallocated' state), which is moved back into the 'stream'. And this line crashes with ifort.

 

Thanks.

andrew_4619
Honored Contributor II
465 Views

OK I understand your usage, I think that is a compiler bug. Maybe some others will comment.

Barbara_P_Intel
Moderator
379 Views

Thanks for the nice reproducer and for the triage tip about changing Class to Type.

I filed a bug report, CMPLRIL0-34514, on your behalf.

In case you are interested, the failure occurs at the

a = Something(200)

statement. We added an ALLOCATED() check after the MOVE_ALLOC. A is not allocated. A should be allocated automatically since it is on the LHS (left hand side) and it is allocatable.

I'll let you know when it is fixed.


Barbara_P_Intel
Moderator
196 Views

This runtime failure is fixed in the current version of ifort, 2021.7.0. It was released last week as part of oneAPI 2022.3.

Please give it a try!



Reply