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

noprotect_constants not working for negative real*8 numbers

Tobias_Loew
Novice
661 Views

Hi,

the following code is compiled with noprotect_constants-option (and without /warn:interfaces) but the debug version generates a runtime exception in the second(!) call to foo. The reason is, that the compiler does not generate a temporary variable for -1.0

      subroutine foo(a)
      real*8 a
      a=42
      end

      program Console

      implicit none
      
      call foo(1.0D0)
      call foo(-1.0D0)  ! <---- error

      end program Console

My compiler-version is  (integrated with VS2008)

Intel(R) Visual Fortran     Package ID: w_fcompxe_2011.1.127
Intel(R) Visual Fortran Composer XE 2011 Integration for Microsoft Visual Studio* 2008, 12.0.3470.2008, Copyright (C) 2002-2010 Intel Corporation
* Other names and brands may be claimed as the property of others.

PS:

Further inspections showed, that the compiler fails to generate the temporary variable if the argument is a compile-time evaluated expression (and negative floats seem to be handled as the expression "minus(absolute value)"). For expression of integers there is the same  wrong behaviour except that negative constants are handled correctly.

IMO this is a serious bug that should be fixed immediately, as programmers rely on the noprotect_constants-option to produce safe code.



0 Kudos
9 Replies
mecej4
Honored Contributor III
661 Views
In this situation, where the program contains errors, I would be happy to see the program abort with access-violation and traceback, so that I am made aware of the existence and location of the error. Secondly, regardless of whether an option such as /assume:protect_constants is in force (not every Fortran compiler may provide such an option), the behavior of the faulty program is ill-defined. If the option is in force, the constant argument may get protection (thereby preserving its value, which is useful if that constant is used elsewhere in the program), but the behavior of the subroutine is ill-defined. Thirdly, I am skeptical of the claim that "programmers rely on the noprotect_constants-option to produce safe code". I hope that they do not. Any option that is complicit in allowing errors to remain hidden is not the programmer's friend. At best, it is a stop-gap. I am puzzled by the statement " the compiler fails to generate the temporary variable if the argument is a compile-time evaluated expression". When an actual argument is an expression, the common way to handle it is to create a temporary variable, assign the value of the expression to the variable and pass the temporary variable as the actual argument. How else would you want the compiler to behave in this case? Or are you asking the compiler to protect even the temporary variable from being overwritten in all cases where the argument is a compile-time constant? What if the argument were -4.0*atan(1.0)? On a different note, you may consider specifying INTENT(OUT) for the subroutine formal argument. That would make it easier for the compiler to catch the incorrect call(s).
0 Kudos
Tobias_Loew
Novice
661 Views
Hi mecej4, thanks for your reply. To point 1: the runtime-error-message is "Unbehandelte Ausnahme bei 0x778a15de (ntdll.dll) in Console2.exe: 0xC0000005: Zugriffsverletzung beim Schreiben an Position 0x004b3290." (sorry for the german; it's an unhandled exception triggered by an access violation (invalid write-operation)) To point 2: You are right that this is not legal FORTRAN. But when Intel invented /assume:protect_constants they decided to extent the language that can be compiled with their compiler. Not adhering to their own extension seems very strange to me. Further, reading the specification of /assume:protect_constants "Tells the compiler to pass a copy of a constant actual argument. This copy can be modified by the called routine, even though the Fortran standard prohibits such modification. The calling routine does not see any modification to the constant." then I infer that the behaviour of the subroutine is well-defined. To point 3: If I understand right: You prefer delivering potentially buggy code that may crash at runtime instead of letting the compiler remove maybe some errors from legacy code. To your last point: I'm only referring to compile-time constant evaluated expression (that are fully evaluated at compile time; thus -4.0*tan(1.0) is just a real-number -6.2296...). In that case the compiler evaluates correctly to -6.2296... but then it does not generate a temporary but transfers the address of some value -6.2296... in RO-section -> crash.
0 Kudos
mecej4
Honored Contributor III
661 Views
Tobias, I looked at the assembler output from your example, and also compared the behavior of the Intel compiler to that of the CVF6.6C compiler, which also provides the /assume:noprotect_constants option. Both the compilers treat the argument -1.0d0 as a constant rather than as an expression. The CVF compiler creates a temporary variable on the stack for both calls to FOO, whereas the Intel compiler fails to do so with -1.0d0 as the argument. As I indicated earlier, the /assume:noprotect_constants is one that I would not use. I am curious to see examples of Fortran programs which function correctly (in the sense of: as a programmer would reasonably expect it to) and this option saves the day. As far as I can see, the option helps keep the problem localized; it somewhat mimics the call-by-value of C for just constant arguments. The fundamental problem -- a subroutine which must modify an argument being called with an argument that must not be modified -- remains unresolved.
0 Kudos
TimP
Honored Contributor III
661 Views
The classic way to protect a constant and still run when an effort was made to modify it, was to add another set of parens () so as to make the compiler see it as an expression. Presumably this is the default effect of -protect-constants. I too fail to see how you could expect to make this function correctly simply by setting a compiler option which basically says don't try to protect me against this error.
0 Kudos
mecej4
Honored Contributor III
661 Views
TimP wrote " Presumably this (to make the compiler see it as an expression) is the default effect of -protect-constants". Rather, if "/assume:noprotect_constants" is not specified, the default is "/assume:protect_constants", and the protection is implemented under Intel Fortran by putting the constant in question in a read-only data segment. At run-time, if the subroutine attempts to write into this segment it causes an access violation. A somewhat far-fetched situation where /assume:noprotect_constants may be useful as a work-around comes to mind. If a function in a pre-compiled library is called from user code with an argument which is almost always used as INTENT(IN), it may be convenient to pass a constant for that argument. The caller essentially implies that he does not have an interest in updates to the argument, if any. The inconsistency in argument remains, but sometimes the user may be unable to get the library vendor to do a proper fix and the work-around is useful.
0 Kudos
jimdempseyatthecove
Honored Contributor III
661 Views
mecej4, >>A somewhat far-fetched situation where /assume:noprotect_constants may be useful as a work-around comes to mind... Correct, however, In order for the said user be able to use that feature, they must have access to the compiler. And in which case, they might as well fix the point of call or the point of use. I recall a circumstance in ~1968 where a user created constant, expressly for obfuscation, whereby the constant(s) were modified in a hidden way. Then these literals were used in an open source (not Open Source) routine. However, now the literals were not now what was expressed in the source. IOW the individual could disclose the algorithm without the required constants .AND. while providing undisclosed errors in the provided code causing countless hours of debugging by others. While there are far-fetched situations, these are generally not in the best interest of the community. Note, you could also make the case for passing the loop control variable (I in DO I=...) to a subroutine, have it modified by that subroutine, then complain that the modified value was not subsequently used by the caller upon return from the call. Supporting this case would likely break code. Jim Dempsey
0 Kudos
mecej4
Honored Contributor III
661 Views
I recall a circumstance in ~1968 where a user created constant, expressly for obfuscation, whereby the constant(s) were modified in a hidden way. Then these literals were used in an open source (not Open Source) routine. However, now the literals were not now what was expressed in the source. IOW the individual could disclose the algorithm without the required constants .AND. while providing undisclosed errors in the provided code causing countless hours of debugging by others.
-- Jim Dempsey. That's an interesting example. I have the impression that vendor extensions to the Fortran standard are not rare, but there are only scant resources for ascertaining the problem(s) that those extensions address.
0 Kudos
jimdempseyatthecove
Honored Contributor III
661 Views
0 Kudos
Steven_L_Intel1
Employee
661 Views
This is a bug that was fixed in a later version of the compiler. I can't look up exactly when it was fixed, but your program works correctly in version 2013.1.
0 Kudos
Reply