Issue with return value of RUNQQ

Issue with return value of RUNQQ

dboggs's picture

In my Quickwin program I am calling the function RUNQQ to launch an external program. Successful execution of the program is supposed to be indicated by the return value. I have noticed a peculiar problem. The relevant program snippet is very simple:

USE IFPORT
IRETURN = RUNQQ ('AnyExec.exe', '-ComlineParam')
IF (IRETURN == -1) PRINT *, 'Application failed'
IF (IRETURN /= -1) PRINT *, 'Application succeeded')

Say that AnyExec.exe does not exist in any searchable path--or say it is not on the computer at all. The function will then return -1, as it should, which can be tested for "application failed". Fine and dandy.

But suppose that someone stupidly (!) forgets to include USE IFPORT. I would expect to get a linker error (unresolved reference), or at least a run time error. But my program runs merrily, returning a seemingly random number from RUNQQ. Testing this value (which is NOT -1), my program happily reports that the application ran successfully.

Needless to say this failed reporting can cause embarassing problems. Why doesn't the compiler or linker report a problem? (and yes I know that EXPLICIT NONE would have helped, but that's another story...)

14 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.
Tim Prince's picture

The only error incurred by omission of USE IFPORT is the incorrect assumption about function return data type. As you say, implicit none, or equivalent command line option, would flag it.

Steve Lionel (Intel)'s picture

As Tim says, without the USE IFPORT, the compiler knows nothing about RUNQQ and follows the Fortran standard implicit typing rules, which happen to lead to an incorrect result. The lesson is to always use IMPLICIT NONE. Always.

Steve
dboggs's picture

OK, thanks for the quick response. And I am fully aware of IMPLICIT NONE and routinely use it; I was just trying to demonstrate a hypothetical problem.

After looking at this again, this "problem" (in my mind) exists because RUNQQ is a function, not a subroutine. If a subroutine, it would be invoked using CALL RUNQQ() and the CALL would enable the linker to flag it as an unresolved external. But invoked as a function, without the USE statement, the compiler can't tell RUNQQ() apart from any other array variable.

As an old-time (DOS) programmer who is struggling with modern (Windows) coding, I am still getting used to the notion of relying so heavily on functions instead of subroutines. To me, invoking procedures using CALL is much more descriptive than just stating the procedure name (as a function). Apparently, it would be much more descriptive to the compiler and linker also. So invoking as a function destroys some of the checking that would be enjoyed if invoking as a subroutine.

Comments?

Steve Lionel (Intel)'s picture

No, the issue has nothing to do with the linker, and you are not losing any error checking by using a function. The problem is that a function, like a variable, has a data type, and if you don't declare the type explicitly, the compiler is required to choose either integer or real depending on the first letter of the name. In this case, RUNQQ is a function that returns an integer, but its name, starting with R, causes an implicit declaration of the type as real. When RUNQQ returns, the result is in one place if an integer and a different place if a real. Since the compiler has the wrong type for the function, it looks in the wrong place and you get bad results.

Intel Fortran does have a feature, Generated Interface Checking, that can detect issues when there are mismatches with your own functions and subroutines, but it doesn't have the information on library routines to check. While we could add a set of generated interfaces for the library routines, there are hundreds of them and some name conflicts which could lead to false errors. If one could turn back the clock, the better choice would be to give the library routines "decorated" names with a prefix different from their Fortran names, so you'd get linker errors if you didn't declare them properly. But for many of these, especially the "portability" routines, they are intended to be called without explicit declaration so this wouldn't work.

My advice is to get in the habit of using IMPLICIT NONE everywhere, adding it where it is missing in your code. Yes, it will mean more work for you, but will save you pain in the long run.

Steve
dboggs's picture

Well, I do use IMPLICIT NONE routinely, that's not the point. And I understand (I think) what you say about the function data type.

What I'd like to clarify is this: If RUNQQ (or many others) were a subroutine instead of a function, my code would have a line like CALL RUNQQ(). Then whether I have implicit none or not, RUNQQ is not affected. When I build this program, wouldn't the compiler or linker produce a flag unless RUNQQ has not been provided for through a USE statement? And if USE has been provided, then the situated is not affected by IMPLICIT NONE--the declaration is provided by the USE module (and in fact if RUNQQ is explicitly declared I believe the compiler will flag an error due to multiple declarations).

More generally, say the routine in question is my own, say MYPROC (ARG), and say I have neglected to include the code for it in my project. If it is a function, my code will have something like IRETURN = MYPROC (ARG) and, if not explicitly declared as a function, the compiler will assume this is a reference to an array named MYPROC and complete the build (leading of course to runtime problems). But if it is a subroutine, my code will have CALL MYPROC (ARG), and during build time it will be flagged as an unresolved external, will it not?

Steve Lionel (Intel)'s picture

Even if RUNQQ was a subroutine, the linker would behave the same whether or not you had the USE because the linker name for RUNQQ is the same as what the compiler would use.

If you used MYPROC as a function, the compiler would assume it was a function unless declared as an array and if there was no MYPROC you'd get a linker error. Same for a subroutine. If you did have a MYPROC in your build but the return type or argument type/number did not match, generated interface checking would (usually) complain.

Steve
dboggs's picture

So if I reference MYPROC without a declaration, I get the expected linker error.Why don't I get a linker error when I referenceRUNQQ, without a USE statement or a type declaration statement?

Steve Lionel (Intel)'s picture

Because RUNQQ is in the default libraries, MYPROC is not.

Steve
dboggs's picture

OK. I think I am having trouble appreciating the distinction between a procedure "being available because it's in a default library" and "being available because it's in a module being USEd'. But this is getting over my head, so let's call it put to bed.

Thanks for putting up with this extended discussion.

sinereh a.'s picture

I need to use RUNQQ command for linking a FORTRAN code with another one. But I have a problem. I have attached a simple example in which the problem occurs. When I run the "testrunqq2.f90" file the "discrete2.f90" is executed itself using RUNQQ command. It seems the command line " result=RUNQQ ('discrete2','-c -r')" does not run the other code at all. I see that the result is given equal to -1 which means the runqq failed! What shoud I do for that to run?

Attachments: 

AttachmentSize
Download discrete2.f90342 bytes
Download testrunqq.f9076 bytes
Steve Lionel (Intel)'s picture

See comments in the other thread where you asked this. When you run from Visual Studio, the default directory is the project directory, not where the EXE is.

Steve
sinereh a.'s picture

Could you please tell me how I can change the default directory?

sinereh a.'s picture

Thanks so much for your reply. The problem I was concerned about is now solved by moving the EXE. file related to the second file from the "debug" folder to the folder where the first code was located.

Login to leave a comment.