- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I decided to share our "bug de jour". The compiler did exactly what we told it to. Why we were passing in the same variable twice and trying to modify it once is a mystery. How any compiler might protect us from our own stupidity is up for debate. Hopefully this is the right forum for everyone to get a good laugh at the bad code below.
After we tracked down the bug, I found a few quotes on Fortran pass by reference with google:
Fortran 77 uses the so-called call-by-reference paradigm. This means that instead of just passing the values of the function/subroutine arguments (call-by-value), the memory address of the arguments (pointers) are passed instead.By default, Fortran passes all data by reference (except the hidden length argument of strings, which is a special case.)
[fxfortran] program main i = 7 print *,'before: ',i call foo(i,i) ! same variable 2x print *,'main: i= ',i end program main subroutine foo(i,j) intent (in) i intent (out) j print *,'foo: ',i,j j= 0 print *,'done: ',i,j end subroutine foo [/fxfortran]OUTPUT
before: 7
foo: 7 7
done: 0 0
main: i= 0
The solution is obvious, dont pass in the same variable twice then zero one, right? Pass by value would put things on the stack but use up more memory and not allow in/out arguments. Don't change the inputs, pass the changed value back as a function.
1 Solution
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The rule in question allows compilers to optimize on the assumption that the dummy arguments are independent of each other (i.e., that changing one will not change another). In this case, ifort didn't do any optimization based on that assumption, so nothing "strange" happened, but in more complicated subroutines, the results can be extremely confusing. (E.g., you might see results that suggest that changing J both changed I and didn't change I.)
The suggestion to use a single argument function instead of a subroutine with one INTENT(IN) and one INTENT(OUT) argument is a good one, but perhaps perhaps a subroutine like FOO is given to you and you don't have the source code to change it. In such a case, you can call FOO without violating the rule like this:
call foo((i),i) ! note the parentheses around the first argument
The parentheses around the first argument tell the compile to pass the value of I rather than the variable itself for the first argument. This doesn't use the same mechanism as call by value (in this case, a temporary containing the value is passed by reference), but the semantic effect is similar. The output from the PRINT statement at line 14 will show that the dummy argument I retains the value 7 even after the dummy argument J is changed, and the program would be legal.
-Kurt
The suggestion to use a single argument function instead of a subroutine with one INTENT(IN) and one INTENT(OUT) argument is a good one, but perhaps perhaps a subroutine like FOO is given to you and you don't have the source code to change it. In such a case, you can call FOO without violating the rule like this:
call foo((i),i) ! note the parentheses around the first argument
The parentheses around the first argument tell the compile to pass the value of I rather than the variable itself for the first argument. This doesn't use the same mechanism as call by value (in this case, a temporary containing the value is passed by reference), but the semantic effect is similar. The output from the PRINT statement at line 14 will show that the dummy argument I retains the value 7 even after the dummy argument J is changed, and the program would be legal.
-Kurt
Link Copied
6 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The code shown is in violation of Note 12.29 of the Fortran 2003 Standard: "If there is a partial or complete overlap between the actual arguments...the overlapped portions shall not be defined, redefined, or become undefined..." In the example code, i and j completely overlap. Therefore, neither is allowed to be changed, and j cannot have intent(out).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Part of the "problem" is lack of understanding of the grammar. "Shall" is an imperative, to say in a different way, it is an order. Some/many/most/all (?) compilers permit you to violate the "shall" clauses, but you do so at your own peril. The reasons for permitting this is due to the large volume of old code that violated this rule. Modern day compilers (with interface declarations) can catch this and eitherwarn or inhibit the coding error. You, as the programmer, mustaccept some level of responsibility for bad programming practices.
Jim Dempsey
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
ifort (and several other Fortran compilers) always had one or more options to compile code which intentionally violates the standard on argument aliasing. Look up /assume:dummy_aliases.
Either that reference on Fortran 77 refers to specific implementations, or it's wrong. Several of us have worked with Fortran 77 compilers which did not use pass by reference. Anyway, that's a different issue from non-standard argument aliasing, which can break the code regardless of argument passing implementation. Often, when people say "my code works with Fortran 77" they don't mean that it complies with standards, in which case the range of unexpected problems should be limited. They mean that it exploits extensions, quirks, and missed diagnoses of some particular implementation.
Either that reference on Fortran 77 refers to specific implementations, or it's wrong. Several of us have worked with Fortran 77 compilers which did not use pass by reference. Anyway, that's a different issue from non-standard argument aliasing, which can break the code regardless of argument passing implementation. Often, when people say "my code works with Fortran 77" they don't mean that it complies with standards, in which case the range of unexpected problems should be limited. They mean that it exploits extensions, quirks, and missed diagnoses of some particular implementation.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I recall the days of early FORTRAN where you could do this
CALL FOO(123.456)
WRITE(U,FMT) 123.456
...
SUBROUTINE FOO(ARG)
REAL ARG
ARG = 654.321
END
and the WRITE(U,FMT) 123.456 would output "654.321"
This is to say you were permitted to shoot yourself in the foot by modifying literals.
Or use this hack to obfuscate yourcode.
Jim Dempsey
CALL FOO(123.456)
WRITE(U,FMT) 123.456
...
SUBROUTINE FOO(ARG)
REAL ARG
ARG = 654.321
END
and the WRITE(U,FMT) 123.456 would output "654.321"
This is to say you were permitted to shoot yourself in the foot by modifying literals.
Or use this hack to obfuscate yourcode.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
And by the way
If the compiler prohibited you from modifying the literal, you could make the claim "the compiler is broken - my program no longer runs".
The newer (FORTRAN IV and later) compilers would either inhibit this behavior or make temp variables of literals and PARAMETERS then pass reference to temp variable. IVF with optimizations can look into the code (I suppose) and avoid the temp creation if the literal is not modified.
Jim
If the compiler prohibited you from modifying the literal, you could make the claim "the compiler is broken - my program no longer runs".
The newer (FORTRAN IV and later) compilers would either inhibit this behavior or make temp variables of literals and PARAMETERS then pass reference to temp variable. IVF with optimizations can look into the code (I suppose) and avoid the temp creation if the literal is not modified.
Jim
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The rule in question allows compilers to optimize on the assumption that the dummy arguments are independent of each other (i.e., that changing one will not change another). In this case, ifort didn't do any optimization based on that assumption, so nothing "strange" happened, but in more complicated subroutines, the results can be extremely confusing. (E.g., you might see results that suggest that changing J both changed I and didn't change I.)
The suggestion to use a single argument function instead of a subroutine with one INTENT(IN) and one INTENT(OUT) argument is a good one, but perhaps perhaps a subroutine like FOO is given to you and you don't have the source code to change it. In such a case, you can call FOO without violating the rule like this:
call foo((i),i) ! note the parentheses around the first argument
The parentheses around the first argument tell the compile to pass the value of I rather than the variable itself for the first argument. This doesn't use the same mechanism as call by value (in this case, a temporary containing the value is passed by reference), but the semantic effect is similar. The output from the PRINT statement at line 14 will show that the dummy argument I retains the value 7 even after the dummy argument J is changed, and the program would be legal.
-Kurt
The suggestion to use a single argument function instead of a subroutine with one INTENT(IN) and one INTENT(OUT) argument is a good one, but perhaps perhaps a subroutine like FOO is given to you and you don't have the source code to change it. In such a case, you can call FOO without violating the rule like this:
call foo((i),i) ! note the parentheses around the first argument
The parentheses around the first argument tell the compile to pass the value of I rather than the variable itself for the first argument. This doesn't use the same mechanism as call by value (in this case, a temporary containing the value is passed by reference), but the semantic effect is similar. The output from the PRINT statement at line 14 will show that the dummy argument I retains the value 7 even after the dummy argument J is changed, and the program would be legal.
-Kurt

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page