- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have a legacy application that is mixed language C++ / Fortran and have upgraded from CVF to Intel Fortran and from Visual Studio 6 to VS 2015.
There is an OLE Server (in C++ with cdecl calling convention) and a bunch of Fortran functions as static LIBs and 2 Fortran DLLs. All Fortran LIB project files are set to use C, REFERENCE calling convention as well as the DLLs
The problems is that I am getting access violation in a Fortran DLL when calling a function pointer that was passed in from the OLE Server.
Here is the sequence with some code samples:
1. C++ OLE Server creates thread using createthreadex.
2. The thread calls Fortran DLL function 'A'
SUBROUTINE A(index)
IMPLICIT NONE
INTERFACE
SUBROUTINE dllFunction (name,
2 environ,
3 addr_rto_get_integer)
!DEC$ATTRIBUTES DLLIMPORT :: dllFunction
!DEC$ATTRIBUTES VALUE :: addr_rto_get_integer
CHARACTER*(*) name
INTEGER*4 environ
END SUBROUTINE dllFunction
END INTERFACE
EXTERNAL rto_get_integer
INTEGER*4 addr_rto_get_integer
addr_rto_get_integer = %LOC(rto_get_integer)
CALL dllFunction (name,
2 environ,
3 addr_rto_get_integer)
RETURN
END
SUBROUTINE dllFunction(name,
2 environ,
3 addr_rto_con_setup)
!DEC$ATTRIBUTES DLLEXPORT :: dllFunction
!!DEC$ATTRIBUTES REFERENCE :: addr_rto_get_integer
INTEGER*4 addr_rto_get_integer
addr_get_integer = addr_rto_get_integer
opti.print = new_rto_get_integer(' ', name, 'print', 0)
END ! optim
2. Common block definition:
INTEGER*4 addr_get_integer
COMMON /opt_addresses/ addr_con_setup,
1 addr_get_integer
POINTER (addr_get_integer, new_rto_get_integer)
INTERFACE
FUNCTION new_rto_get_integer(list, item, field, sub)
INTEGER*4 new_rto_get_integer
!DEC$ATTRIBUTES C, alias:'_NEW_RTO_GET_INTEGER':: new_rto_get_integer
CHARACTER*(*) list
CHARACTER*(*) item
CHARACTER*(*) field
INTEGER*4 sub
END FUNCTION new_rto_get_integer
END INTERFACE
4. When the dllFunction tries to use the function pointer addr_rto_get_integer an access violation occurrs.
opti.print = new_rto_get_integer(' ', name, 'print', 0) <<<--- Access violation
Any ideas?
An example of the function in the common block is shown below:
INTERFACE
FUNCTION new_rto_get_integer(list, item, field, sub)
INTEGER*4 new_rto_get_integer
!DEC$ATTRIBUTES C, alias:'_NEW_RTO_GET_INTEGER':: new_rto_get_integer
CHARACTER*(*) list
CHARACTER*(*) item
CHARACTER*(*) field
INTEGER*4 sub
END FUNCTION new_rto_get_integer
END INTERFACE
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
One of the issues in porting from CVF to Intel Fortran is that of how to pass the hidden arguments containing the lengths of character string arguments. Your DLL function may expect the CVF calling convention to be used and, if so, you need to specify /iface:cvf. For details, see https://software.intel.com/en-us/node/525130 .
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Not quite sure why that would cause an access violation when calling a callback function. Don't really want to revert the calling convention back to make it compatible with the old CVF as that seems a step back.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Is the callback function written in C++? If so, as mecej4 says, then it needs to be altered to account for the change in calling convention associated with the change in compiler (or tell the Fortran compiler to use the previous calling convention), otherwise it will be looking for things in its argument list that are not the things it expects (rather than getting a character length, it will get a machine pointer value, or rather than getting a machine pointer value it will get a character length). Regardless of the language it is written in, perhaps show the relevant declarations for the actual call back procedure.
Perhaps things have been elided for the sake of example, but there are a number of other issues. Where is `index` declared in subroutine `A`? In dllFunction, none of the dummy arguments are declared, and `addr_rto_get_integer` appears to be referenced when undefined. What is `opti`?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Mark I. wrote:
Not quite sure why that would cause an access violation when calling a callback function. Don't really want to revert the calling convention back to make it compatible with the old CVF as that seems a step back.
The callback function, if it has character string arguments and is written in Fortran, expects the string lengths to be passed to it in a certain way (CVF convention, probably). Unless you change the source code of the caller (in the OLE server?), you cannot use a new callback function that follows the Intel Fortran default calling convention.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I edited the code to reduce size.
The callback function is a Fortran function with the default calling convention.
SUBROUTINE rto_put_integer(list, object, field, sub, value) CHARACTER list*(*), object*(*), field*(*) INTEGER*4 sub INTEGER*4 value
'opti' is a record in a common block:
'index' is n INTEGER*4 - guess I removed it when editing the code for publishing..
STRUCTURE /OPT_INTS/ INTEGER*4 nv ! number of variables INTEGER*4 nc ! number of constraints INTEGER*4 type ! Optimiser Type INTEGER*4 lp_option ! LP Option INTEGER*4 max_opt ! Max Optimisation Iterations INTEGER*4 max_fps ! Max Feasible Point Iterations INTEGER*4 max_iter ! .. used for either (dynamic) INTEGER*4 max_relax ! Max Relaxation Steps INTEGER*4 update ! Update B or H matrix INTEGER*4 formula ! Use DFP or BFGS INTEGER*4 print ! Diagnostic print controller INTEGER*4 vdid ! Virt. disp. ID of "Running..Optimiser" box INTEGER*4 liwork ! Size of Integer Work Space INTEGER*4 lwork ! Size of Real Work Space INTEGER*4 iter_opt ! Optimisation Iterations INTEGER*4 iter_fps ! Feasible Point Iterations INTEGER*4 max_hess ! Max Hessian Resets INTEGER*4 ncf_type ! Type used by E04NCF INTEGER*4 num_qpa ! No. of calls to qpapprox INTEGER*4 num_opm ! No. of calls to opt_plant_model INTEGER*4 lun ! LUN used for diagnostics INTEGER*4 phase ! Current Phase INTEGER*4 NNZ ! No of non-zeros in Jacobian INTEGER*4 environ ! Underlying Model Package INTEGER*4 naughty ! Pick on a bad constraint INTEGER*4 verify ! Verify level INTEGER*4 dv_level ! Derivative level INTEGER*4 scale_opt ! Scale option INTEGER*4 max_cold ! No. of COLD starts, before we go WARM INTEGER*4 spare(3) ! END STRUCTURE RECORD /OPT_INTS/ opti
In the solution there are lot of Fortran files that declare the dummy arguments and others that don't. This worked on CSV without issue (It's a program ported from VAX, then MS Fortran, then CVF and now Intel :-)). I did want to make then all the same but ended up leavinng them alone. I only have to worry about dummy string lengths with mixed language calls rather than same language calls, right?
I could try creating a parameter less callback and see if that gets the access violation too to check that it's not a parameter problem.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If your OLE server was written to work with CVF, its expected function prototype is
void rto_put_integer( char *list, int l_list, char *object, int l_object, char *field, int l_field, int *sub, int *value );
With Intel Fortran, with the default calling convention, the actual function prototype is
void rto_put_integer( char *list, char *object, char *field, int *sub, int *value, int l_list, int l_object, int l_field );
The "hidden length arguments" are l_list, l_object and l_field.
You can use the /iface:mixed_str_len_arg compiler option to make Intel Fortran use the CVF convention. See https://software.intel.com/en-us/node/579741 . Since you are already able to link, STDCALL and the @nn name decoration of CVF are probably irrelevant.
This may be a good time to replace the nonstandard STRUCTURE and RECORD features of VAX Fortran, using the standard "derived data types" of Fortran 90 and later.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The 'rto_get_integer' function is defined in the same DLL as the function that calls the callbacks and not in the OLE server. I didn't think you needed to add the dummy arguments if Fortran is calling Fortran?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Mark I. wrote:
I didn't think you needed to add the dummy arguments if Fortran is calling Fortran?
Correct (for the string length arguments).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Any more ideas guys? I'm really stuck on this.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Not sure if I can help and the answer to my question is probably in code you haven't shown, but I do not see the variable name defined in your routine A. Is it a module variable or am I simply overlooking it?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I found the code snippets a a bit confusing to follow. The heading "2. Common block definition: " has the interface to new_rto_get_integer is this "common block" actually part of an include file? When we have the call:
opti.print = new_rto_get_integer(' ', name, 'print', 0) <<<--- Access violation
can we actual see the explicit interface of new_rto_get_integer, we need to? Clearly you will also get an access violation if this function tries to modify parameters 1,3 and 4 as they are passed as constants (yes I know stating the obvious but we can all sometimes suffer "code blindness" and non of the calls you show specify INTENT).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Andrew,
The common block is in a seperate include file.
The function new_rto_get_inteteger never gets executed as the access violation occurrs when trying to call the function but the new_rto_get_integer doesn't modify the params.
We all get code blind at times :-))
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Mark I. wrote:
Any more ideas guys? I'm really stuck on this.
I'm afraid that this thread is too fragmented and disorganized. At best, we could add to the confusion by doing more speculation.
If you want more useful comments, you can post complete simplified example code(s) that we can compile and run ourselves, and (i) works with CVF and (ii) does not work with IFort. It may be best to start a new thread with that.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page