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

Assignment of allocatable character substring on itself fails sometimes

vvnurmi
Beginner
1,000 Views

Hi,

Assigning a slice of an allocatable character string onto the character string itself produces garbage sometimes:

CHARACTER(LEN = :), ALLOCATABLE :: S S = 'TESTING' S = S(3:)

Garbage *doesn't* appear if the character string is not allocatable. Garbage doesn't appear also if assignment is done via another variable.

I'm using Intel Visual Fortran Compiler Professional for applications running on IA-32, Version 11.1 Build 20091130 Package ID: w_cprof_p_11.1.054. This behaviour has been tested also on the latest Intel Visual Fortran Compiler, in which case the behaviour was different but still not as one would expect.

Here is a small program to demonstrate the effect.

PROGRAM ASSIGNMENT_TEST CHARACTER(LEN = 20) :: TEST_DATA INTEGER :: SKIP = 3 TEST_DATA = '1234567890ABCDEFGHIJ' DO I = SKIP, 9 CALL TESTS(I) END DO CONTAINS SUBROUTINE TESTS(I) INTEGER :: I CHARACTER(LEN = :), ALLOCATABLE :: S ! Write dummy data to S to reveal what is copied where S = 'abcdefghijklmnopqrst' S = TEST_DATA(1:I) WRITE (*,*) 'S LENGTH = ', LEN(S) WRITE (*,*) 'S : ', S WRITE (*,*) 'Expected : ', S(SKIP:) S = S(SKIP:) WRITE (*,*) 'Actual : ', S WRITE (*,*) END SUBROUTINE TESTS ENDPROGRAM ASSIGNMENT_TEST

When run, the program outputs the following. Note differences with string lengths 6 and 7:

S LENGTH = 3 S : 123 Expected : 3 Actual : 3 S LENGTH = 4 S : 1234 Expected : 34 Actual : 34 S LENGTH = 5 S : 12345 Expected : 345 Actual : 345 S LENGTH = 6 S : 123456 Expected : 3456 Actual : 545f S LENGTH = 7 S : 1234567 Expected : 34567 Actual : 5f5fg S LENGTH = 8 S : 12345678 Expected : 345678 Actual : 345678 S LENGTH = 9 S : 123456789 Expected : 3456789 Actual : 3456789
0 Kudos
1 Solution
Wendy_Doerner__Intel
Valued Contributor I
1,000 Views
I reproduced and reported to engineering the concerns in this thead. I will update the thread when we have a compiler which fixes this. For reference the engineering tracking number is: DPD200158840

------

Wendy

Attaching or including files in a post

View solution in original post

0 Kudos
8 Replies
anthonyrichards
New Contributor III
1,000 Views
Put S(1:) = S(SKIP:) in stead of S = S(SKIP:) and it works (IVF 11.1.065)
0 Kudos
mecej4
Honored Contributor III
1,000 Views
I thought of the same change, and the alternatives of S(:) on the left or ADJUSTL(the right), but refrained from posting them because they may not do what the OP wanted: readjust the length of S to what is just needed for the contents, without additional blanks.

Here is a simpler example:

[fortran]    program tst
character(len=:), allocatable :: S
S='abcdef'
S=S(3:)
write(*,'("|",A,"|",I2)')S,LEN(S)
S='abcdef'
S(1:)=S(3:)
write(*,'("|",A,"|",I2)')S,LEN(S)
end program tst
[/fortran]
The output from Ifort 11.1.072 on Linux x64 is
[bash]|| 4
|cdef | 6

[/bash]
The first result line should have been

|cdef| 4

This shows both the differences in the resulting string length and the bug in the Intel compiler. For the assignment on line 4, F2003 rules require that the compiler emit code to keep a copy of the r.h.s. expression as needed to avoid using deallocated memory (the old allocation of S) after reallocation of S, which is done before copying the expression into it.

0 Kudos
anthonyrichards
New Contributor III
1,000 Views
Why should you expect the compiler to add code to deallocate S and reallocate it again when all it has is the statement

S=S(SKIP:)

?
0 Kudos
John4
Valued Contributor I
1,000 Views

@anthonyrichards: Because that's what the deferred-length character (i.e., CHARACTER(LEN=:), ALLOCATABLE :: S) should do. the The deferred-length character feature is based on the reallocation on assignment (a Fortran 2003 feature), which means the left-hand side must always be deallocated and reallocated again to the length of the right-hand side, except when a stride is used (as in your example, S(:) ).

In Intel's implementation, reallocation on assignment is disabled by default, except for character(:) variables ---and allocatable components of derived types, I guess.

@vvnurmi: In the past, I reported a similar problem, with substrings not being handled properly ---it's not exactly the same problem, except if you think it in terms of Fortran's INTERFACE ASSIGNMENT (e.g., as if the assignment were expressed as a call to some internal subroutine).

As a workaround, you can add an empty string at the end, e.g.:

[fortran]S = S(SKIP:)//''[/fortran]

0 Kudos
mecej4
Honored Contributor III
1,000 Views
Because S is declared to be an allocatable variable of deferred type parameter, i.e., CHARACTER (len=:).

Please see Sec. 7.4.1.3, especially Note 7.35, in the F2003 standard draft, J3/04-007, to which a link is located at the top of this forum. Or see Sec. 17.5.2 of Metcalf, Reid and Cohen, Fortran 95/2003 Explained, OUP, 2006. It is clear that "vvnurmi" was posting about this F2003 feature.
0 Kudos
Wendy_Doerner__Intel
Valued Contributor I
1,001 Views
I reproduced and reported to engineering the concerns in this thead. I will update the thread when we have a compiler which fixes this. For reference the engineering tracking number is: DPD200158840

------

Wendy

Attaching or including files in a post

0 Kudos
mecej4
Honored Contributor III
1,000 Views
I am curious to know what led you to the workaround! I would have thought that a smart compiler with optimizations turned on would recognize that concatenating with a zero-length string could be treated as a no-op.
0 Kudos
John4
Valued Contributor I
1,000 Views

As I said before, I just thought of the assignment as a call to a subroutine (e.g., s_assign_s(lhs, rhs) ). So, forcing a copy of the second argument seemed like the obvious thing to do.

That's analogous to the trick of ensuring a null-terminated buffer when dealing with the Windows API (e.g., TRIM(string)//''C ). So maybe that's why there's no optimization in that regard.

0 Kudos
Reply