I want to detect from inside a subroutine that a dummy argument passed with intent(in)
is actually a null pointer:
program testPTR
implicit none
integer, target :: ii
integer, pointer :: iPtr
iPtr => ii
iPtr = 2
print *, "passing ii"
call pointer_detect(ii)
print *, "passing iPtr"
call pointer_detect(iPtr)
iPtr => null()
print *, "passing iPtr => null()"
call pointer_detect(iPtr)
contains
subroutine pointer_detect(iVal)
implicit none
integer, intent(in), target :: iVal
integer, pointer :: iPtr
character(len = *), parameter :: sub_name = 'pointer_detect'
iPtr => iVal
if (associated(iPtr)) then
print *, "Pointer associated. Val=", iVal, ", iPtr = ", iPtr
else
print *, "Pointer not associated. Val=", iVal, ", iPtr = ", iPtr
endif
end subroutine pointer_detect
end program
To my surprise it works with gfortran-9 and gfortran-12. However I have got a couple of questions:
- How legitimate, portable and Fortran-ish the check is?
- For some reason it does not segfault on the last print, but rather prints zeros and exits cleanly:
$ gfortan test.f90
$ ./a.out && echo ok
passing ii
Pointer associated. Val= 2 , iPtr = 2
passing iPtr
Pointer associated. Val= 2 , iPtr = 2
passing iPtr => null()
Pointer not associated. Val= 0 , iPtr = 0
ok
$
Any ideas? Thank you!
CodePudding user response:
The fragment
iPtr => null()
print *, "passing iPtr => null()"
call pointer_detect(iPtr)
violates the Fortran standard and makes your program invalid (Fortran 2008, 25.5.2.3):
Except in references to intrinsic inquiry functions, a pointer actual argument that corresponds to a nonoptional nonpointer dummy argument shall be pointer associated with a target.
The dummy argument of the non-intrinsic procedure is neither optional, nor a pointer.
Responsibility for avoiding this problem is entirely the programmer's and the compiler has no duty to detect this broken code for you.
A compiler may well be able to detect such bugs, if asked, however (usually at run time):
At line 19 of file brokenpointer.f90
Fortran runtime error: Pointer actual argument 'iptr' is not associated
being the output when using gfortran and the compile option -fcheck=pointer
, or
forrtl: severe (408): fort: (7): Attempt to use pointer IPTR when it is not associated with a target
with ifort's -check pointers
.
The programmer cannot reliably do similar checks within the procedure itself, because a Fortran compiler is under no obligation to respect the programmer who breaks the rules in this way.
Looking at the procedure's efforts here, for example:
iPtr => iVal
if (associated(iPtr)) then
iVal
is not a pointer, so iPtr
becomes associated with that variable in that pointer assignment. The compiler is allowed to assume you haven't broken the rules of Fortran, so iptr
is associated and that test condition is always true. There is no valid Fortran program in which that test condition can resolve to false.
However, not all hope is lost. The text from the standard I quote says something other than "nonpointer": it says "nonoptional". If iVal
is instead optional use PRESENT()
:
subroutine pointer_detect(iVal)
implicit none
integer, intent(in), optional :: iVal
character(len = *), parameter :: sub_name = 'pointer_detect'
if (present(iVal)) then
print *, "Actual argument pointer was associated. Val=", iVal
else
print *, "Actual argument pointer was not associated."
endif
end subroutine pointer_detect
A nonpointer, nonallocatable, optional dummy argument will be treated as not present if associated with a disassociated pointer actual argument.
Note, however, that this won't help you if iPtr
is of undefined association status. Nothing will.
CodePudding user response:
call pointer_detect(iPtr)
is not standard-conforming if the pointer is null. The routine pointer_detect()
is poorly named, as it cannot detect anything about the original pointer, which is simply not passed: the dummy argument is not a pointer, so upon the call the compiler will pass the address of the target of iPtr
, not iPtr
itself. But if iPtr
is null then it has no target: the behavior gets undefined.
An undefined behavior is, well, undefined. Or say unpredictable. It could crash, or output unpredictable values, etc... This kind of violation of the standard cannot really be detected at compile-time, and the compiler is not required to do so. gfortran may have compilation options that enable the detection at runtime, though (with performance penalty, as with any other runtime check).