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

Copy of un unallocated character array in a type

Le_Callet__Morgan_M
1,667 Views

Since upgrading to OneApi 2023.2 and Visual Studio Professional 2022 (64-bit) - LTSC 17.6 I have some existing code when try something along the following line:

s1=s2

where s1 and s2 are a Type containing  among standard types (various fixed size array of real, integers) a variable defined as : character(len=:), allocatable :: mydata

 

One way I got it to NOT crash was to define an assignment procedure:

        procedure, private, pass(sin) :: assign_ MyType

        generic, public   :: assignment(=) => assign_ MyType

inside which I have this code

    ! only copy the allocatable character if allocated

    if(allocated(sin%fname)) then

        sout%mydata=  sin%mydata

     endif

 

This seems to have fixed the crash but I wanted to know if it was a known issue or just luck as I cannot reproduce it with a simple example.

 

Thanks

0 Kudos
12 Replies
Le_Callet__Morgan_M
1,599 Views

Clearly I should have written this message more carefully.

What I meant is that WITHOUT the explicit assignment procedure it crashes.

I was wondering if anyone had issues copying unallocated array of characters ?

Thanks

0 Kudos
IanH
Honored Contributor II
1,532 Views

Not had problems like this with the compiler recently.

Your follow up post asks about array of characters, your original post describes a scalar character component.  Neither as components should require the defined assignment.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,588 Views

The following reproducer shows similar behavior (unexpected)

!  AssignEmptyArray.f90 
program AssignEmptyArray
    implicit none
    real, allocatable :: OutputArray(:), InputArray(:), EmptyArray(:)
    allocate(InputArray(100))
    print *, size(OutputArray)
    OutputArray = InputArray
    print *, size(OutputArray)
    OutputArray = EmptyArray
    print *, size(OutputArray)
end program AssignEmptyArray
...
           0
         100
         100

The expected result for the last print statement would be 0.

 

Jim Dempsey

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,588 Views

Additional info.

 

!  AssignEmptyArray.f90 
program AssignEmptyArray
    implicit none
    real, allocatable :: OutputArray(:), InputArray(:), EmptyArray(:)
    allocate(InputArray(100))
    print *, size(OutputArray)
    OutputArray = InputArray
    print *, size(OutputArray)
    OutputArray = EmptyArray
    print *, size(OutputArray)
    allocate(EmptyArray(0))
    OutputArray = EmptyArray
    print *, size(OutputArray)
end program AssignEmptyArray
...
           0
         100
         100
           0

 

Apparently there is a difference between:

Never been allocated allocatable array

  and

Allocated to empty allocatable array

 

@Le_Callet__Morgan_M 

Perhaps on your user defined type initialization code, you could allocate a zero length character variable (and in place of, or in addition to, using ...allocated(variable),  you test for length of 0 or all spaces).

 

Jim Dempsey

 

0 Kudos
andrew_4619
Honored Contributor III
1,559 Views

In F2008 (haven't checked 2018)  It says the argument of SIZE "shall not be an unallocated allocatable variable"  thus the code is not valid so the answer is undefined.  use of  if ( allocated(thing)) is my  recommendation.

0 Kudos
FortranFan
Honored Contributor III
1,536 Views

@Le_Callet__Morgan_M ,

Please explain and illustrate the problem you face with suitable details including what you mean by "crash".  Preferably you will share with the Intel team and the readers here your specific error scenario.

If for any reason (e.g., proprietary codebase?) you can't do so, take the following which does NOT reveal any issue with Intel oneAPI 2023.2.0 but then adapt it to demonstrate the problem.

   type :: t
      integer :: n = 0
      character(len=:), allocatable :: s
   end type
   type(t) :: a, b
   a%n = 42
   b = a
   print *, "b%n = ", b%n, "; expected is ", a%n 
   print *, "allocated(b%s)? ", allocated(b%s), "; expected is F"
end 
C:\temp>ifort /free /standard-semantics p.f
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.10.0 Build 20230609_000000
Copyright (C) 1985-2023 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.36.32537.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
 b%n =  42 ; expected is  42
 allocated(b%s)?  F ; expected is F

C:\temp>ifx /free /standard-semantics p.f
Intel(R) Fortran Compiler for applications running on Intel(R) 64, Version 2023.2.0 Build 20230627
Copyright (C) 1985-2023 Intel Corporation. All rights reserved.

Microsoft (R) Incremental Linker Version 14.36.32537.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
 b%n =  42 ; expected is  42
 allocated(b%s)?  F ; expected is F

C:\temp>
0 Kudos
Le_Callet__Morgan_M
1,474 Views

Dear all, thanks.

One of the issue i have is that i cannot create a simple type that caused the issue when compiled alone.

This is my type:

    module Test

   

    type::tType

        integer            :: rec1(20) = 0

        integer            :: rec2(8) = 0

        integer            :: rec3_a(10,6) = 0

        integer            :: rec3_b(10,2) = 0

        integer            :: rec4_a(5) = 0

        real               :: rec4_b(2) = 0.0

        integer            :: rec4_c = 0

        integer            :: rec5(6) = 0

        integer            :: rec6 = 0

        real               :: rec7(4) = 0.0

        integer            :: rec8_a = 0

        character(len=256) :: rec8_b = ''

        integer            :: rec9(3) = 0

        integer            :: nrecords = 9

        character(len=:), allocatable :: fname

    end type tType   

    end module Test

used as like this

    program Console1

    use Test

    implicit none

   

    ! Variables

   

    type(tType) :: t1,t2

    ! Body of Console1

    print *, 'copy type'

    !if(allocated(t1%fname)) then

    t1=t2

 

end program Console1

 

The example above will NOT crash in a simple program but will crash (at t1=t2) within a more complex program.

@jimdempseyatthecove  I am not sure i understand your suggestion 

"Perhaps on your user defined type initialization code, you could allocate a zero length character variable (and in place of, or in addition to, using ...allocated(variable),  you test for length of 0 or all spaces).

"

What would this look like for your example ?

 

Thanks and regards

 

0 Kudos
IanH
Honored Contributor II
1,428 Views

There have been compiler bugs in this area historically, but equally what you describe could be due to memory corruption from a separate erroneous part of your code.  A typical approach to isolate the cause of the problem (and/or generate a minimum example for a compiler bug report is to progressively cut your program down - a "binary chop" approach or similar.  For large code bases I have sometimes spent a day or two doing this, which is costly, but ultimately both necessary and worth it.

Alternatively, using the debugger you may be able to determine what it is that is causing the program to crash at the time it crashes (e.g. the descriptor for the allocatable character scalar component has become corrupted in some way).  If the crash is relatively reproducible you can then set data breakpoints on the relevant parts of the descriptor to see which bit of wayward code is causing the corruption, when you run it for a second time (at least...) in the debugger.

At this stage I would concentrate more on identifying the cause than implementing a work around.  If the cause is a fault in your code - you want it fixed.  If the cause is a fault in the compiler you (and the rest of us!) also want it fixed - that will take longer, but while waiting for a fix you will want to understand the implications.

(There are lots of explicit shape array components in that derived type... run off the end of those and chaos will result...)

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,464 Views

Hmm, well this is interesting:

module Test
    type::tType
        integer            :: rec1(20) = 0
        integer            :: rec2(8) = 0
        integer            :: rec3_a(10,6) = 0
        integer            :: rec3_b(10,2) = 0
        integer            :: rec4_a(5) = 0
        real               :: rec4_b(2) = 0.0
        integer            :: rec4_c = 0
        integer            :: rec5(6) = 0
        integer            :: rec6 = 0
        real               :: rec7(4) = 0.0
        integer            :: rec8_a = 0
        character(len=256) :: rec8_b = ''
        integer            :: rec9(3) = 0
        integer            :: nrecords = 9
        character(len=:), allocatable :: fname
    end type tType
end module Test

program Console1
    use Test
    implicit none
    character(len=0) :: empty
    type(tType) :: t1, t2
    t2%fname = empty
    print *, 'copy type'
    !if(allocated(t1%fname)) then
    t1=t2
end program Console1

**** place break point on print (line 27) ****

jimdempseyatthecove_0-1692622457905.png

Notes:

The above was ifort, 32-bit build

 

Note variable EMPTY is CHARACTER(0)

t1%fname, which was not expressly allocated, nor assigned to (aka defined), is a character variable of len=4 containing '    '

t2%fname, which was not expressly allocated, but assigned to (aka defined) a character variable who's len=0, results in a character variable who's len=4 and contains junk data.

Note, prior to t2%fname = empty, t2%fname contained a character variable of len=4 containing '    '

 

On ifort, 64-bit build, same situation except the before t2%fname = empty, t1 and t2 fname is a character variable of len=8 containing '        '

 

ifx, x64-bit build

 

Variable EMPTY appears as "undefined pointer/array" of type CHARACTER(*)

(ifort correctly had this as a defined ('') of type CHARACTER(0) )

After the assignment (t2%fname = empty), fname becomes defined as 'junkjunk', an eight character CHARACTER(*) variable.

 

Some weird behavior going on.

 

Jim Dempsey

 

 

 

 

0 Kudos
andrew_4619
Honored Contributor III
1,459 Views

 

 

 

program Console1
    implicit none
    character(len=0) :: empty
    character(len=:), allocatable :: t1, t2
    t2 = empty
    print *, 'copy type'
    t1 = t2
end program Console1

 

 

 

The behaviour @jimdempseyatthecove describes  is not related to derived types as the above program behaves in the same way in the debugger.

EDIT but maybe that is some debugger integration quirk as print *, 'copy type', len(t2), sizeof(t2) generates 0 (zero) in both cases.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,447 Views

Andrew,

I could not get the sample program to fail (OP mentioned simple reproducer did not show symptoms).

My post, was an attempt to construct a work around. And in the process, noted peculiarities (?bugs?,?undefined behavior?) as noted in the debug session.

 

character(len=0) :: empty

 

ifort shows the expected '' character(0) variable. IOW a character variable of len=0

ifx shows unexpectedly undefined pointer/array character(*). I presume this is a bug.

 

ifx, character(len=:), allocatable :: t1, t2

Prior to being defined, shows the len=4 with blanks.

*** However, inserting print *,len(t2%fname) does show len=0 ***

Therefore the Debugger integration seems incorrect whereas the runtime len(...) returns the correct/expected length

 

It testing the t1=t2, at least on my system, the code produces the expected results.

 

On my system, v 2023.1, it would seem

IF(LEN(T2%FNAME)==0) ...

Would be a suitable test for an unallocated, character(len=:) variable.

IOW this does not error/crash. As to if this will hold true for future versions, I cannot say.

 

Additional side note:

program Console1
    use Test
    implicit none
    character(len=0) :: empty
    type(tType) :: t1, t2
    print *, len(t2%fname), allocated(t2%fname)
    t1=t2
    print *, len(t1%fname), allocated(t1%fname)
    t2%fname = '123456789'
    print *, len(t2%fname), allocated(t2%fname)
    t1=t2
    print *, len(t1%fname), allocated(t1%fname)
    t2%fname = empty
    print *, len(t2%fname), allocated(t2%fname)
    t1=t2
    print *, len(t1%fname), allocated(t1%fname)
    deallocate(t2%fname)
    print *, len(t2%fname), allocated(t2%fname)
    t1=t2
    print *, len(t1%fname), allocated(t1%fname)
end program Console1

shows

0 F

0 F

9 T

9 T

0 T

0 T

0 F

0 F

 

The execution is correct (as expected).

@Le_Callet__Morgan_M 

There must be some other nuance with your failing code that is not expressed in your failing (crashing) code.

Jim Dempsey

0 Kudos
Le_Callet__Morgan_M
1,284 Views

Dear All,  many thanks. I ll update you when i found out where it is going wrong.

 

0 Kudos
Reply