- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sorry to ask yet another question!
I have a routine in Fortran that has been compile as CVF (as the version of NAG requires the CVF calling convention) below:
LOGICAL*4 FUNCTION set_process_name (name, len1) !DEC$ATTRIBUTES ALIAS : '_SET_PROCESS_NAME@8' :: set_process_name IMPLICIT NONE CHARACTER name*32 INTEGER*4 len1, len2 INTEGER*4 i LOGICAL*4 fin ProcessName = " " fin = .FALSE. DO i = 1, 32 IF ((Name(i:i) .GT. ACHAR(0)) .AND. (fin .EQ. .FALSE.)) THEN ProcessName(i:i) = Name(i:i) ELSE fin=.TRUE. END IF END DO set_process_name = .TRUE. RETURN END
The Fortran settings are
/nologo /debug:full /Od /I"Debug/" /I"..\Incl/" /I"C:\build\Intel Fortran RTO+ Calculation Engine\Sources\Solve\Debug/" /reentrancy:threaded /extend_source:132 /fpscomp:nolibs /debug-parameters:used /warn:declarations /warn:ignore_loc /fpe:1 /fp:source /names:uppercase /iface:cvf /module:"Debug/" /object:"Debug/" /Fd"Debug\vc140.pdb" /traceback /check:stack /libs:dll /threads /dbglibs /winapp /c
This Fortran routine called by a routine that is located inside an C++ MFC OLE Server compiled using stdcall as the default calling convention.
BOOL Application::SetProcessName(LPCTSTR p_Name) { long lDum = 0; TRY { if (strncmp(p_Name, "###", 3) == 0) { LPCTSTR m_Name; m_Name = &p_Name[3]; MonitorServer = (char *) malloc (strlen(m_Name) + 1); strcpy (MonitorServer, m_Name); } else { if (ProcessName == NULL) { free (ProcessName); } ProcessName = (char *) malloc (strlen(p_Name) + 1); // ----------------------------------- // Set the process name in the fortran // ----------------------------------- SET_PROCESS_NAME(p_Name, &lDum); strcpy (ProcessName, p_Name); } return TRUE; } CATCH_ALL (e) { THROW_LAST(); } END_CATCH_ALL return FALSE; }
The settings for the C++ are
/FR".\Debug\" /GS- /analyze- /W3 /Gy /Zc:wchar_t- /I"..\HysysLink/" /I"..\DXSConnect/" /ZI /Gm /Od /Fd".\Debug\" /Zc:inline /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MT" /D "_VC80_UPGRADE=0x0600" /D "_MBCS" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gz /Oy- /MDd /Fa".\Debug\" /EHsc /nologo /Fo".\Debug\" /Fp".\Debug\RtoOle.pch"
The Fortran routine is declared in C++ as
extern "C" long __stdcall SET_PROCESS_NAME(LPCTSTR, long *);
After the ' return FALSE' line is executed the CheckESP raises an exception 'Run-time check failure 0 - T'.
The call stack is below
RtoOle.exe!failwithmessage(void * retaddr, int crttype, int errnum, const char * msg) C++
RtoOle.exe!_RTC_Failure(void * retaddr, int errnum) C++
RtoOle.exe!_RTC_CheckEsp() C++
> RtoOle.exe!Application::SetProcessName(const char * p_Name) Line 5654 C++
[External Code]
RtoOle.exe!WinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, char * lpCmdLine, int nCmdShow) Line 26 C++
[External Code]
I thought that setting the calling convention in C++ for the Fortran routine is all that is needed to ensure that the routine is called properly with the correct stack handling.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You used __stdcall in the C++ routine. This is NOT the C++ default and you attempted to paper over it by explicitly specifying an alias to Fortran including the name decoration, without telling Fortran it was STDCALL. This corrupts the stack. It worked in CVF because STDCALL was the CVF default, but it's not in Intel Fortran.
There are other problems. The NAME argument to the Fortran routine is type CHARACTER. This implies a hidden length argument that you didn't pass.
There are several ways to fix this, but the simplest seems to be:
- Remove __stdcall from the C++ declaration
- Remove the ATTRIBUTES directive you have in the Fortran routine
- Add "!DEC$ ATTRIBUTES REFERENCE :: name" after the declaration of the NAME dummy argument.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Paper over it, I like that!
I previously, set the compiler options for the C++ to use __stdcall as the default, as a possible workaround to an issue I had calling a NAG routine so I would have to reset this to use cdecl to follow your suggestions. I'll give it a try.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you want to use __stdcall, replace the ATTRIBUTES directive for set_process_name with:
!DEC$ ATTRIBUTES CVF :: set_process_name
You still need ATTRIBUTES REFERENCE for the name argument.
In general, any time you put explicit decoration (especially the @n) in an ALIAS, that's a sign that you've made a mistake. We do offer a DECORATE attribute to let the compiler do the correct decoration for the platform and calling convention.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page