Last week I forgot to fill a CHARACTER*4 with the year ‘2008’.
As a result, the directory where my application was looking for its input
was a bogus string containing two consecutive slashes and which obviously did not exist.
Nevertheless, INQUIRE tells me that that file does exist and my program proceeds and crashes trying to read it…
Below you’ll find a narrowed down piece of code.
If you replace the part '/home/dijkva/'by an existing directory
on your machine, then you’ll probably get the same result as I get:
the first attempt via the main program tells you that ‘myfile’ does not exist.
The second attempt however suggests successful probing!
I am running:
pgf90 6.1-4 32-bit target on x86-64 Linux
Copyright 1989-2000, The Portland Group, Inc. All Rights Reserved.
Copyright 2000-2006, STMicroelectronics, Inc. All Rights Reserved.
I did not use any fancy compile-switches. Just “pgf90”.
Is this a bug in the compiler?
When compiled with e.g. g95 both calls tell me that the file does not exist.
Regards,
Arjan
MODULE LibUtil
IMPLICIT NONE
PRIVATE
PUBLIC :: FileExists,MyRoutine
CONTAINS
FUNCTION FileExists(Directory,FName)
CHARACTER(*), INTENT(INOUT) :: FName,Directory
LOGICAL :: FileExists,DumLog
CHARACTER(256) :: MyString
MyString = TRIM(Directory)//TRIM(FName)
WRITE(*,'(A)') 'Just before it happens... "'//TRIM(MyString)//'"'
INQUIRE(FILE=TRIM(MyString),EXIST=DumLog)
FileExists = DumLog
END FUNCTION FileExists
SUBROUTINE MyRoutine()
CHARACTER(256) :: FName,Directory
LOGICAL :: DumLog
CHARACTER :: YearStr*4
FName = 'myfile'
! WRITE(YearStr,'(I4)') 2008 ! this is the line that I forgot to code...
Directory = '/home/dijkva/' // YearStr // '/'
DumLog = FileExists(Directory,FName)
WRITE(*,*) DumLog
END SUBROUTINE MyRoutine
END MODULE LibUtil
PROGRAM Test
USE libutil
IMPLICIT NONE
CHARACTER(256) :: Directory,FName
LOGICAL :: DumLog
Directory = '/home/dijkva//'
FName = 'myfile'
DumLog = FileExists(Directory,FName)
WRITE(*,*) DumLog
CALL MyRoutine()
END PROGRAM Test
It’s not compiler bug. Since YearStr in uninitialized, it can contain random garbage. In 32-bits, it happens to be “\0” so the filename turns into a legal file name. If we also compile it 64-bits, then the garbage gets translated into " " and the inquire fails.
Example:
arroyo:/tmp/qa% pgf90 -o test test.f90 -V6.1-7 -tp k8-32
arroyo:/tmp/qa% test
Just before it happens... "//tmp/qa//myfile"
T
Just before it happens... "//tmp/qa//myfile"
T
arroyo:/tmp/qa% pgf90 -o test test.f90 -V6.1-7 -tp k8-64
arroyo:/tmp/qa% test
Just before it happens... "//tmp/qa//myfile"
T
Just before it happens... "//tmp/qa/ /myfile"
F
It’s not compiler bug. Since YearStr in uninitialized, it can contain random
garbage. In 32-bits, it happens to be “\0” so the filename turns into a legal
file name. If we also compile it 64-bits, then the garbage gets translated
into " " and the inquire fails.
Sorry, Mat, but I don’t understand your explanation.
To which file do you suggest that the following string refers?
/home/dijkva/\0/myfile
This is what would result if in my sample YearStr is replaced by “\0”.
I can hardly imagine that this will be something meaningful.
Directory /home/dijkva/ does not contain a file named “myfile”!
That file is located in /home/dijkva/2008/ but I had forgotten to include the
year as a string in the path and therefore INQUIRE should not have
confirmed existence in that wrong directory!
And: doesn’t it matter if there are redundant slashes in a pathname,
as in /home/dijkva//myfile ?
Directory /home/dijkva/ does not contain a file named “myfile”!
Correct, but by inadvertently adding a NULL character in the middle of the string, you’re actually inquiring if “/home/dijkva/” exists not /home/dijkva/myfile". For example, when I change the root directory to a non-existent directory, the inquire fails as expected.
arroyo:/tmp/qa% test
Just before it happens... "//tmp/qa//myfile"
F
Just before it happens... "//tmp/nothere//myfile"
F
Unfortunately, using uninitialized variables can lead to unpredictable results.
And: doesn’t it matter if there are redundant slashes in a pathname,
as in /home/dijkva//myfile ?
by inadvertently adding a NULL character in the middle of the string, you’re
actually inquiring if “/home/dijkva/” exists
Ah!
Thanks!
So I added a string-terminator (or something similar) instead of a string?
I am still a bit puzzled by the fact that I can print a string with
a NULL character in the middle as if nothing is wrong.
Maybe I was (am) hoping that this would be shown some way when I print
that string, e.g. by having the string printed in 2 pieces or some other sign
of evidence. Apparently not the case.
Thanks again!
The difference is because INQUIRE’s file name needs to be turned into a C null-terminated character string in order to interface with the OS function that checks if the file exists. A Fortran string does not use null-terminator so the whole string is printed.