Multiple Fortran DLL calls return corupt data

Multiple Fortran DLL calls return corupt data

I have two old fortran programs that are supposed to be talking to each other, originally both writen and compiled using old Compaq compiler. Recently we switched due to various reasons to the Intel compiler and except for a few minor incompartibility issue the code for both programs compiles nicelly.

Program 1 is a DLL, and program 2 makes multiple calls of that dll. The dll creates as an output a text file which is then read by program 1. The output for the first 3 calls is ok, the 4th call and all calls after return only gibberish. I made a small test where I called the dll 8 times with the identical input, same problem, results 1 to 3 are ok, result 4 and up are garbage.

I've searched these forums and have seen that this can be due to thge stack corruption if the calling convention is not explicitly defined (as in STDCALL), however this then leads to the an unresolved external symbol error from the linker. I'm a bit of a "hobby programmer", so I was hoping that a more experienced user can point me to a simple solution for this problem.

Here is an example of the code:

------ PROGRAM 1 ---------

Real*8 FUNCTION DLLTEST(INFILE, OUTFILE, DLLFLAG)

INTERFACE

REAL*8 FUNCTION DLLTEST(INFILE, OUTFILE, DLLFLAG)

!DEC$ ATTRIBUTES DLLEXPORT, STDCALL, ALIAS: 'DLLTEST' :: DLLTEST

CHARACTER*200 INFILE, OUTFILE

INTEGER DLLFLAG

END FUNCTION

END INTERFACE

.....internal workings....

END FUNCTION

------ PROGRAM 2 ---------

INTERFACE

REAL*8 FUNCTION DLLTEST(INFILE, OUTFILE; DLLFLAG)

!DEC$ ATTRIBUTES DLLIMPORT, STDCALL, ALIAS: 'DLLTEST' :: DLLTEST

CHARACTER*200 INFILE, OUTFILE

INTEGER DLLFLAG

END FUNCTION

END INTERFACE

REAL*8 DUMMY

multiple calls to: DUMMY = DLLTEST(INFILE, OUTFILE, DLLFLAG)

---> The DLLTEST.lib is specified as dependancy for Program2, but linker produces following error: LNK2019: unresolved external symbol __imp__DLLTEST reference in function _MAIN__

Removing STDCALL and ALIAS resolves the problem but leads to call stack corruption during multiple calls. Any help and pointers would be apreciated. Thanks in advance.

Alexander

4 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

In the code for your DLL it looks like you have an interface body that declares a procedure that has the same name as the function that hosts the interface body.  This is an error.  With appropriate compiler options (perhaps /warn:all and maybe /stand) I'd expect the compiler to complain. 

A consequence of that error is likely that the calling convention specified for the function itself is not STDCALL, and this is inconsistent with the calling convention for the function specified in the interface block in your main program.  This sort of mismatch in calling convention will cause stack issues.

The attributes that you are applying to the function in the interface body should instead be applied directly to the "top level" function.  The interface body in the function must then be deleted.

In the main program you retain the interface body for the function - the interface body effectively tells the compiler "somewhere else I have defined a function that looks like this".  The declaration of the function in the main program and the definition of the function itself must be consistent.  (That consistency can practically be achieved by copy and paste.)

i.e - you want something like:

! ------ The function in the DLL ("program 1") ---------
Real(8) FUNCTION DLLTEST(INFILE, OUTFILE, DLLFLAG)
  !DEC$ ATTRIBUTES DLLEXPORT, STDCALL, ALIAS: 'DLLTEST' :: DLLTEST
  CHARACTER*200 INFILE, OUTFILE
  INTEGER DLLFLAG
  .....internal workings....
END FUNCTION

! ------ Main program ("program 2") ---------
INTERFACE
  REAL(8) FUNCTION DLLTEST(INFILE, OUTFILE, DLLFLAG)
    !DEC$ ATTRIBUTES DLLIMPORT, STDCALL, ALIAS: 'DLLTEST' :: DLLTEST
    CHARACTER*200 INFILE, OUTFILE
    INTEGER DLLFLAG
  END FUNCTION
END INTERFACE
REAL(8) DUMMY
DUMMY = DLLTEST(INFILE, OUTFILE, DLLFLAG)
...

Notes:

- The real*n syntax is a common extension that hurts my eyes, so I've changed it above to the equivalent (for the Intel compiler) standard syntax.

- For new code you would put your function in a MODULE, then USE that module inside the main program and delete the interface block.  Use of modules allows the compiler to "know" the details that you supply via an interface block automatically, which significantly reduces the potential for programmer error.

- Whether you still want the STDCALL and ALIAS attributes (which specify aspects of the calling convention) depends on your requirements, but if you don't care about the details of the calling convention used then you could get rid of either or both of them.  If you are not sure of your requirements, then leave them there.

Thanks for the reply Ian, the setup that you are proposing is basically what I've had at the start, but without STDCALL and ALIAS attributes. It works in as far that the both the DLL and then the executable compile without any problems, but then during the run time and multiple calls to the DLL (4 in my case) the whole thing breaks down.

With STDCALL and ALIAS, when I try to compile the executable I get a linker error 2019 like : uresolved external symbol _DLLTEST referenced  in function _MAIN__

Any ideas?

Ian!!! Thanks, for your diligence. One of your notes mentioned using MODULES to define the interface block. That was the root of the cause of my problems. The DLL was called from different subroutens in the program 2 and the interface block was declared only in the main function. The problem occured when DLL was called from one of the subroutines and then again from the main function. It finally clicked that maybe I should USE the module in all subroutines where the DLL is being called. Again thanks alot for your help.

Leave a Comment

Please sign in to add a comment. Not a member? Join today