Disappointments with -C run-time checks.
Sun Fortran's run-time checks are too strict, and are aborting on code that is actually valid, but might be considered bad usage. Unfortunately, there are no options to select which code checks should be enforced. It would be nice to at least have an option to issue warnings when errors are not detected, but to continue running. Is there any way to do this, even as a hack?
One example is issuing an error on transfer statements when the source and destination byte sizes do not match. Automatic truncation of the data is a feature of TRANSFER, not an extension. So, such use is not an error.
Another example is that it does not allow using NULL pointers as procedure arguments. A NULL argument is perfectly valid as long as the called procedure knows not to use it. The newer standards have more details on the valid use of NULL arguments. In some case, using optional arguments is probably a better alternative, so it may be viewed as bad coding practice. However, if several such arguments are used, this imposes the need for many CALL variations where only one is really needed. It would be nice if Fortran would explicitly define NULL as equivalent to "not present" for optional arguments.
[1216 byte] By [
Joe_Krahna] at [2007-11-27 10:51:15]

# 1
Are you talking about dbx run-time checking (RTC) feature? If so, you can use 'bcheck' script to perform memory access checking in batch mode. bcheck --help will tell you about the options.
However, RTC doesn't know (and care) much about source language, so yes, it is rather strict. For example, if you have 4-byte integer variable and you initialize it with "1" and compiler has generated code that actually stores only one byte in the variable, RTC would consider the rest three uninitialized (this is artificial example just to give you general idea, I guess it can't happen in the real world).
# 2
(Maxim, Joe is talking about the Fortran compiler's -C flag, not dbx rtc.)
> Sun Fortran's run-time checks are too strict, and are
> aborting on code that is actually valid, but might be
> considered bad usage. Unfortunately, there are no
> options to select which code checks should be
> enforced. It would be nice to at least have an option
> to issue warnings when errors are not detected, but
> to continue running. Is there any way to do this,
> even as a hack?
The support library routines call "abort" after printing their error messages. You could define an "abort" function that would override the system function.
You could also define functions that would override the support library functions, but that would be more time consuming. Let me know if you would prefer to do this. I can give you the interface definitions.
> One example is issuing an error on transfer
> statements when the source and destination byte sizes
> do not match. Automatic truncation of the data is a
> feature of TRANSFER, not an extension. So, such use
> is not an error.
I can't reproduce this. Can you give me an example?
> Another example is that it does not allow using NULL
> pointers as procedure arguments. A NULL argument is
> perfectly valid as long as the called procedure knows
> not to use it. The newer standards have more details
> on the valid use of NULL arguments. In some case,
> using optional arguments is probably a better
> alternative, so it may be viewed as bad coding
> practice. However, if several such arguments are
> used, this imposes the need for many CALL variations
> where only one is really needed. It would be nice if
> Fortran would explicitly define NULL as equivalent to
> "not present" for optional arguments.
I'm also having trouble reproducing this. Can you give an example?
igba at 2007-7-29 11:30:04 >

# 3
> The support library routines call "abort" after
> printing their error messages. You could define an
> "abort" function that would override the system
> function.
>
> You could also define functions that would override
> the support library functions, but that would be more
> time consuming. Let me know if you would prefer to
> do this. I can give you the interface definitions.
>
I tried an alternate abort() function, but it leads to corruption because abort is supposed to be a no-return function. Instead, I wrote a replacement to
__f95_null_pointer_err() and __f90_shape_err(). I am guessing at the interfaces, but it works well. Here is my code for the null pointer handler. I can print the same message, but I don't know what the arguments labeled "n1" and "flag" are.
subroutine sunf95_null_pointer_err(object, n1, line, column, file, flag) &
bind (C,name="__f95_null_pointer_err")
use, intrinsic :: ISO_C_Binding, only:
character(len=99) :: file, object
integer, value :: n1, line, column, flag
integer :: object_len, file_len
object_len=index(object,char(0))-1
file_len=index(file,char(0))-1
write(*,'(/,A,/,3A,/,2(A,I0),3A)') &
" ****** FORTRAN RUN-TIME SYSTEM ****** ", &
" Attempting to use an unassociated POINTER '",object(:object_len),"'", &
" Location: line ",line," column ",column," of '",file(:file_len),"'"
end subroutine sunf95_null_pointer_err
> > One example is issuing an error on transfer
> > statements when the source and destination byte
> sizes
> > do not match. Automatic truncation of the data is
> a
> > feature of TRANSFER, not an extension. So, such
> use
> > is not an error.
>
> I can't reproduce this. Can you give me an example?
>
I found that this only applies when the output of transfer() is an array, and the sizes do not match. If the optional size argument is included, it is not seen as an error. Here is an example:
program test
implicit none
integer :: a(1)
integer :: b(2)
a=transfer(b,a)! array-size error
a=transfer(b,a,1) ! no error
end program test
> > Another example is that it does not allow using
> NULL
> > pointers as procedure arguments. A NULL argument
> is
> > perfectly valid as long as the called procedure
> knows
> > not to use it. The newer standards have more
> details
> > on the valid use of NULL arguments. In some case,
> > using optional arguments is probably a better
> > alternative, so it may be viewed as bad coding
> > practice. However, if several such arguments are
> > used, this imposes the need for many CALL
> variations
> > where only one is really needed. It would be nice
> if
> > Fortran would explicitly define NULL as equivalent
> to
> > "not present" for optional arguments.
>
> I'm also having trouble reproducing this. Can you
> give an example?
I found that this one occurs only with array pointers. Here is an example:
program test
implicit none
integer, pointer :: p(:) => NULL()
call noop(p)
end program test
subroutine noop(arg)
integer :: arg(*)
end subroutine noop
# 4
> > > Another example is that it does not allow using
> > NULL
> > > pointers as procedure arguments.
> > [...]
> > I'm also having trouble reproducing this. Can you
> > give an example?
> I found that this one occurs only with array
> pointers. Here is an example:
>
> program test
> implicit none
> integer, pointer :: p(:) => NULL()
> call noop(p)
> end program test
> subroutine noop(arg)
>integer :: arg(*)
> end subroutine noop
I'm afraid this isn't legal Fortran. According to the standard (12.4.1.2): "...if the dummy argument is not a pointer and the corresponding actual argument is a pointer, the actual argument shall be associated with a target..."
# 5
> > > > Another example is that it does not allow
> using
> > > NULL
> > > > pointers as procedure arguments.
> > > [...]
> > > I'm also having trouble reproducing this. Can
> you
> > > give an example?
> > I found that this one occurs only with array
> > pointers. Here is an example:
> >
> > program test
> > implicit none
> > integer, pointer :: p(:) => NULL()
> > call noop(p)
> > end program test
> > subroutine noop(arg)
> >integer :: arg(*)
> > end subroutine noop
>
> I'm afraid this isn't legal Fortran. According to
> the standard (12.4.1.2): "...if the dummy argument is
> not a pointer and the corresponding actual argument
> is a pointer, the actual argument shall be associated
> with a target..."
You are right, and it still is that way in F2008. That is a stupid restriction, like many in Fortran. I assume that the idea is that optional arguments should be used when an argument is meant to be "undefined". But, if I want to call a subroutine that has 4 optional arguments, I would need 16 different versions of the subroutine call to handle all possibilities. The work-around is (obviously) to assign unused pointers to a dummy target.
As for handling RT checks, I think it would be nice to allow a selection of checks to be implemented. A simpler solution would be to leave things as they are, but give an option for errors not to trigger an abort().
# 6
> I assume that the idea is that optional arguments
> should be used when an argument is meant to be
> "undefined". But, if I want to call a subroutine that
> has 4 optional arguments, I would need 16 different
> versions of the subroutine call to handle all
> possibilities.
I'm not quite understanding the issue you're getting at. If the subroutine had 4 optional arguments it could be called with none of them, all of them, or any combination in between -- whatever suits the purpose.Why would there need to be 16 different versions of the call? (or subroutine?)
In your example, how could the subroutine know whether arg was defined or undefined? If optional arguments really don't fit the need, you could declare the dummy arguments to be pointers. Then you could test their association status. Alternatively in F2003, allocatable actual and dummy arguments, and test with allocated.
# 7
> > I assume that the idea is that optional arguments
> > should be used when an argument is meant to be
> > "undefined". But, if I want to call a subroutine
> that
> > has 4 optional arguments, I would need 16
> different
> > versions of the subroutine call to handle all
> > possibilities.
>
> I'm not quite understanding the issue you're getting
> at. If the subroutine had 4 optional arguments it
> could be called with none of them, all of them, or
> any combination in between -- whatever suits the
> purpose.Why would there need to be 16 different
> versions of the call? (or subroutine?)
The subroutine that I am calling from can have any combination of the arguments representing data. The ones in use depend on some global state settings. I want to call another subroutine with 4 matching optional arguments. If the system allows for any combination of data to be active, I have to consider all 16 possible call variations.
>
> In your example, how could the subroutine know
> whether arg was defined or undefined? If optional
> arguments really don't fit the need, you could
> declare the dummy arguments to be pointers. Then you
> could test their association status. Alternatively
> in F2003, allocatable actual and dummy arguments, and
> test with allocated.
The child subroutine in this case does a lot of work, and declaring an argument as a pointer is a big performance hit. I could use allocatables, but pointers are more useful in this case. The advantage of having this child subroutine is to avoid the performance penalty of pointers.
I think that the newer standards (maybe F2008?) state that an optional argument can be used to call another procedure with an optional argument, and be valid as either data or not-present. I think it would be a great feature to simply allow a similar rule for a NULL pointer to an optional argument to be considered as valid but not present the same as a not-present dummy arg.
# 8
> __f95_null_pointer_err() and __f90_shape_err(). I am
> guessing at the interfaces, but it works well. Here
> is my code for the null pointer handler. I can print
> the same message, but I don't know what the arguments
> labeled "n1" and "flag" are.
Here are the function interfaces:
void __f95_missing_optional_err(char *dummy_name, int src_line, int src_col, char *src_file)
void __f95_null_pointer_err(char *sym_name, int is_allocatable, int src_line, int src_col,char *src_file)
void __f90_shape_err(int dim, int size, int size2, int src_line, int src_col,char *src_file)
void __f90_shape_err_long(int dim, long long size, long long size2, int src_line, int src_col,char *src_file)
void __f90_reshape_err(int size, int size2, int src_line, int src_col,char *src_file)
void __f90_reshape_err_long(long long size, long long size2, int src_line, int src_col,char *src_file)
void __f90_shape_arguments_err(int dim, int size, int size2, int src_line, int src_col,char *src_file,char *function_name)
void __f90_cb_error( int subscr_num, int value, char *array_name,
int src_line, int src_col, char *src_file)
void __f90_cb_err_str( int subscr_num, int value, char *array_name,
int src_line, int src_col, char *src_file)
void __f90_cb_error_long( int subscr_num, long long value, char *array_name,
int src_line, int src_col, char *src_file)
void __f90_cb_err_str_long( int subscr_num, long long value, char *array_name,
int src_line, int src_col, char *src_file)
Let me know if the variable names aren't sufficiently descriptive.
> I found that this only applies when the output of
> transfer() is an array, and the sizes do not match.
> If the optional size argument is included, it is not
> seen as an error. Here is an example:
> program test
> implicit none
> integer :: a(1)
> integer :: b(2)
> a=transfer(b,a)! array-size error
> a=transfer(b,a,1) ! no error
> end program test
It turns out that the compiler is correct in issuing the error. The standard defines transfer like this:
"The result is of the same type and type parameters as MOLD...
Case (ii): If MOLD is an array and SIZE is absent, the result is an array and of rank one.
Its size is as small as possible such that its physical representation is not shorter
than that of SOURCE."
In other words, the actual shape of the MOLD argument is ignored. I don't know why the standard was written this way. It doesn't seem terribly useful.
igba at 2007-7-29 11:30:04 >

# 9
> I think that the newer standards (maybe F2008?) state
> that an optional argument can be used to call another
> procedure with an optional argument, and be valid as
> either data or not-present.
I think that's part of f95 at least. Maybe even f90.
> I think it would be a
> great feature to simply allow a similar rule for a
> NULL pointer to an optional argument to be considered
> as valid but not present the same as a not-present
> dummy arg.
That's an interesting idea. I'll mention it to our standards rep.
igba at 2007-7-29 11:30:04 >

# 10
> The child subroutine in this case does a lot of work,
> and declaring an argument as a pointer is a big
> performance hit.
By the way, we have done some work recently to improve the performance of pointers. In many cases, there is no longer a performance hit from using them. We still have some gaps to fill, of course, but it may be good enough for your purposes.
igba at 2007-7-29 11:30:04 >

# 11
> > The child subroutine in this case does a lot of work,
> > and declaring an argument as a pointer is a big
> > performance hit.
>
> By the way, we have done some work recently to
> improve the performance of pointers. In many cases,
> there is no longer a performance hit from using them.
> We still have some gaps to fill, of course, but it
> may be good enough for your purposes.
It would be very helpful if Fortran had the concept of restricted pointers. The standards people push for using allocatables, but pointers can be useful. I have taken the approach of using calling a child subroutine to un-taint pointers from aliasing considerations. I have seen other people request some form of restricted pointers, but it seems that the standards people don't like the idea because it is hard to enforce by the compiler. It is the programmers responsibility not to use aliased arguments without risking errors. Likewise, the programmer can be equally responsible for not aliasing pointers.
If you are working to avoid the performance hit of pointers, it seems that a restricted attribute would be a good language extension. That way, you could fully optimize with pointers and not worry about breaking the case where pointers really are aliased. I generally disfavor language extensions, but pointer support has been rather poor.
# 12
> > I think it would be a
> > great feature to simply allow a similar rule for a
> > NULL pointer to an optional argument to be
> considered
> > as valid but not present the same as a not-present
> > dummy arg.
>
> That's an interesting idea. I'll mention it to our
> standards rep.
I don't like this idea at all. A null pointer could easily be a legitimate thing to pass as an optional argument (the procedure allocates it or points it at something, e.g.) ; having this be equivalent to "not present" really isn't defensible.
# 13
> > > I think it would be a
> > > great feature to simply allow a similar rule for
> a
> > > NULL pointer to an optional argument to be
> > considered
> > > as valid but not present the same as a
> not-present
> > > dummy arg.
> >
> > That's an interesting idea. I'll mention it to
> our
> > standards rep.
>
> I don't like this idea at all. A null pointer could
> easily be a legitimate thing to pass as an optional
> argument (the procedure allocates it or points it at
> something, e.g.) ; having this be equivalent to "not
> present" really isn't defensible.
I think it is defensible, but only for the case when the dummy argument is not a pointer. In that case, NULL is never legitimate, so why not allow it to represent something meaningful instead?
# 14
It seems that the standards committee is already considering this extension:
http://j3-fortran.org/doc/year/06/06-112.pdf
igba at 2007-7-29 11:30:04 >
