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

Reading file of length zero

Diehl__Martin
Novice
3,194 Views

I have a general reading routine that crashes for empty files (ASCII).

The following minimal example shows this behavior (compile; touch empty.txt; ./out) when compiled with ifort version 19.0.2.187. Is that the expected behavior, i.e. would I need to check for fileLength/=0 or is ifort suppost to figure this out.

program test

 character(len=:), allocatable :: a
 a = IO_read('empty.txt')

 print*, len(a)
 print*, '#'//a//'#'

contains

function IO_read(fileName) result(fileContent)

  character(len=*),  intent(in) :: fileName
  character(len=:), allocatable :: fileContent
  integer ::  &
    fileLength, &
    fileUnit, &
    myStat

  inquire(file = fileName, size=fileLength)
  open(newunit=fileUnit, file=fileName, access='stream',&
       status='old', position='rewind', action='read',iostat=myStat)
  if(myStat /= 0) stop 1
  allocate(character(len=fileLength)::fileContent)
  read(fileUnit) fileContent
  close(fileUnit)

end function IO_read

end program test

 

0 Kudos
1 Solution
Steve_Lionel
Honored Contributor III
3,024 Views

Here's my analysis of the situation...

The READ is attempting to read zero bytes from an empty file connected for unformatted stream access. The standard says that an end-of-file condition occurs when "an attempt is made to read beyond the end of a stream file." Since the READ is not trying to read beyond the end of the file, the file position should remain unchanged and the READ should succeed.

Therefore, I believe this is an error on the part of ifort and should be reported to Intel using the Online Service Center.

View solution in original post

0 Kudos
32 Replies
Steve_Lionel
Honored Contributor III
780 Views

That's interesting, and another bug. Let me do some tests on that.

0 Kudos
John_Campbell
New Contributor II
780 Views

Why not simply respond to " inquire(file = fileName, size=fileLength)" for empty (size=0) or non-existent (size=-1), without opening the file.

Perhaps use  if ( fileLength <= 0) then ; allocate(character(len=0)::fileContent) ; else ; ...

Isn't fileLength = -1 already a problem ?

0 Kudos
Diehl__Martin
Novice
780 Views

John Campbell wrote:

Why not simply respond to " inquire(file = fileName, size=fileLength)" for empty (size=0) or non-existent (size=-1), without opening the file.

Perhaps use  if ( fileLength <= 0) then ; allocate(character(len=0)::fileContent) ; else ; ...

The first solution leaves fileContent unallocated which requires further checks in other parts of the code (the MWE given here is not the full code).

A non-existing file is certainly a problem, but I sometimes have optional files and simply check whether they exist (with inquire)

In general, I prefer to write code without special cases.

Unfortunately, the use of modern Fortran reveals often compiler glitches (not just in Intel products) that require to use a non-optimal solution. Hence, when in doubt I try to clarify whether my code is invalid or whether the compiler does not respect the standard.

0 Kudos
Steve_Lionel
Honored Contributor III
780 Views

I can't reproduce the iostat comparison issue you mentioned in post 21. The iostat properly comes back as -1 and comparing /= 0 works.

0 Kudos
Diehl__Martin
Novice
780 Views

Dear Steve,

many thanks for your investigations. Actually, I think my explanation was a little bit misleading.

  • If I read a file of length N, N>0, into a string of length N, the iostat return value is 0. Hence, I assume an error for iostat /= 0 (error: iostat > 0, read beyond EOF: iostat = -1).
  • If I read a file of length 0 into a sting of length 0, the iostat return value is -1. This seems to be a contradiction to your statement from the standard which states that -1 is returned if "an attempt is made to read beyond the end of a stream file." According to my understanding, reading 0 bytes from a 0 bytes file should also result in iostat = 0 because EOL was not reached (file length matches length of read). Due to this unexpected behavior, I need to change my code to accept an iostat of -1, even though this signals that I tried to read more information than present in the file

Finally, just for the sake of completeness (I understand that you have confirmed that already): If the iostat argument for the read statement is missing I get an segmentation fault if reading a 0 length file. This behavior is cured if iostat is present as an actual argument

0 Kudos
andrew_4619
Honored Contributor II
780 Views

It would be better to use the variable with the IOSTAT_END parameter of the intrinsic module ISO_FORTRAN_ENV, or the IS_IOSTAT_END function. 

0 Kudos
Diehl__Martin
Novice
780 Views

andrew_4619 wrote:

It would be better to use the variable with the IOSTAT_END parameter of the intrinsic module ISO_FORTRAN_ENV, or the IS_IOSTAT_END function. 

many thanks, I did not know about this. Much easier to read

0 Kudos
Steve_Lionel
Honored Contributor III
780 Views

Diehl, Martin wrote:

  • If I read a file of length 0 into a sting of length 0, the iostat return value is -1. This seems to be a contradiction to your statement from the standard which states that -1 is returned if "an attempt is made to read beyond the end of a stream file." According to my understanding, reading 0 bytes from a 0 bytes file should also result in iostat = 0 because EOL was not reached (file length matches length of read). Due to this unexpected behavior, I need to change my code to accept an iostat of -1, even though this signals that I tried to read more information than present in the file

Right - that's a bug. You should be getting iostat=0 for reading zero bytes as you are not attempting to read past the end of file.

0 Kudos
jimdempseyatthecove
Honored Contributor III
780 Views

>>You should be getting iostat=0 for reading zero bytes as you are not attempting to read past the end of file.

What is supposed to happen when you issue this 0-byte read, as the next read following a >0 byte read that returned EOF (-1)?
IOW the internal state is "read beyond end of file". This may present a different behavior should the file be opened for shared use or for exclusive use.

Martin, had your test program (legitimately) encountered an EOF return... then issued the 0-byte read?

Jim Dempsey

0 Kudos
Steve_Lionel
Honored Contributor III
783 Views

If the READ does not attempt to transfer data, it should not get an EOF condition, no matter where it is in a file connected for stream access. It is different for non-stream access.

0 Kudos
Diehl__Martin
Novice
783 Views

jimdempseyatthecove (Blackbelt) wrote:

Martin, had your test program (legitimately) encountered an EOF return... then issued the 0-byte read?

No, the file is just opened (as in the example given in my initial post)

0 Kudos
Steve_Lionel
Honored Contributor III
409 Views

Intel informs me that this bug was fixed in the latest compiler release (compiler 2021.5.0, oneAPI HPC Toolkit 2022.1.) I had to argue a bit with the developers on this one, as they initially claimed the behavior was appropriate... I verified that the correct behavior is now seen.

0 Kudos
Reply