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

Run time check failure

Mark_I_1
Beginner
323 Views

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.

 

0 Kudos
3 Replies
Steven_L_Intel1
Employee
323 Views

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.
0 Kudos
Mark_I_1
Beginner
323 Views

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.

 

 

0 Kudos
Steven_L_Intel1
Employee
323 Views

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.

0 Kudos
Reply