- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, i got an access violation when entering the function c_testfunction. It gives the message: "Attempt to use pointer FOO_C when it is not associated with a target". It is not associated, because it is meant to be allocated in the C++ function. It works as intendet without the /CA option.
Fortran part:
! Compile: ifort.exe /nologo /CA /stand:f18 /O2 /traceback /module:obj\W64\ /c main.f90 /object:obj\W64\main.obj
! Link: ifort.exe /nologo /exe:bin\W64\F_EXE.exe bin\W64\C_DLL.lib obj\W64\main.obj /link
program hello
use, intrinsic :: iso_c_binding
interface
subroutine c_testfunction(foo_c) bind(C, name="c_testfunction")
import
integer(c_int), pointer, intent( out) :: foo_c(:,:)
end subroutine
end interface
integer, allocatable :: bar(:,:)
call f_testfunction(bar)
write(*,*) bar
contains
subroutine f_testfunction(foo_f)
integer, allocatable, intent( out) :: foo_f(:,:)
integer(c_int), pointer :: foo_c(:,:)
foo_c => null()
call c_testfunction(foo_c)
write(*,*)foo_c
allocate(foo_f, source = foo_c)
end subroutine
end program
C++ Part (While not important i guess):
// dllmain.h
#pragma once
#include "ISO_Fortran_binding.h"
#ifdef STEPIMPORTDLL_EXPORTS
#define STEPIMPORTDLL_API extern "C" __declspec(dllexport)
#else
#define STEPIMPORTDLL_API extern "C" __declspec(dllimport)
#endif
STEPIMPORTDLL_API int c_testfunction(CFI_cdesc_t* foo_c);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//dllmain.cpp
#include "dllmain.h"
// Compile: /JMC /permissive- /GS /W3 /Zc:wchar_t /ZI /Gm- /Od /sdl /Fd"x64\Debug\vc142.pdb" /Zc:inline /fp:precise /D "_DEBUG" /D "CDLL_EXPORTS" /D "_WINDOWS" /D "_USRDLL" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /FC /Fa"x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /diagnostics:column
// Link: /OUT:"..\F_EXE\bin\W64d\C_DLL.dll" /MANIFEST /NXCOMPAT /PDB:"..\F_EXE\bin\W64d\C_DLL.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" "libifcoremdd.lib" /IMPLIB:"..\F_EXE\bin\W64d\C_DLL.lib" /DEBUG /DLL /MACHINE:X64 /INCREMENTAL /PGD:"..\F_EXE\bin\W64d\C_DLL.pgd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /ManifestFile:"x64\Debug\C_DLL.dll.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
int c_testfunction(CFI_cdesc_t* foo_c)
{
int e;
CFI_index_t dim1 = 2;
CFI_index_t dim2 = 4;
CFI_index_t lower_bounds[] = { 1,1 };
CFI_index_t upper_bounds[] = { dim1, dim2 };
int is_established = CFI_establish(foo_c, NULL, CFI_attribute_pointer, CFI_type_int, 0, 2, NULL);
int is_allocated = CFI_allocate(foo_c, lower_bounds, upper_bounds, 0);
e = (is_established == CFI_SUCCESS) && (is_allocated == CFI_SUCCESS) ? 0 : -1; // If allocation failed then e = -1
if (is_allocated == CFI_SUCCESS)
{
int* array = (int*)foo_c->base_addr;
for (CFI_index_t i = 0; i < dim2; ++i)
{
array[i*2] = i;
array[i*2+1] = i*10;
}
}
return e;
}
Optimizing options do not seem to influence this.
Is this an error in my code or is this a compiler bug?
Thanks in advance.
This happens with Inter Fortran Compiler 19.1 Update 0 to 2 (PSXE20)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No, that's not it - the C++ code does have extern "C" through the declaration.
I think this would be an ifort bug in that the pointer array is INTENT(OUT) and ifort should not be checking to see if it is associated. This is probably an edge case in the F2018 C interoperability stuff that wasn't checked for.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Retry with extern "C" attribute in your C function in your CPP code
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No, that's not it - the C++ code does have extern "C" through the declaration.
I think this would be an ifort bug in that the pointer array is INTENT(OUT) and ifort should not be checking to see if it is associated. This is probably an edge case in the F2018 C interoperability stuff that wasn't checked for.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I can't build the cdll:
1>------ Rebuild All started: Project: cppdll, Configuration: Debug Win32 ------
1>dllmain.cpp
1>D:\c\vs2019\icom\cppdll\ISO_Fortran_binding.h(156,20): warning C4200: nonstandard extension used: zero-sized array in struct/union
1>D:\c\vs2019\icom\cppdll\ISO_Fortran_binding.h(156,20): message : This member will be ignored by a defaulted constructor or copy/move assignment operator
1> Creating library D:\c\vs2019\icom\Debug\cppdll.lib and object D:\c\vs2019\icom\Debug\cppdll.exp
1>dllmain.obj : error LNK2019: unresolved external symbol _for_CFI_allocate referenced in function _c_testfunction
1>dllmain.obj : error LNK2019: unresolved external symbol _for_CFI_establish referenced in function _c_testfunction
1>D:\c\vs2019\icom\Debug\cppdll.dll : fatal error LNK1120: 2 unresolved externals
1>Done building project "cppdll.vcxproj" -- FAILED.
2>------ Rebuild All started: Project: hello, Configuration: Debug Win32 ------
2>Deleting intermediate files and output files for project 'hello', configuration 'Debug|Win32'.
2>Compiling with Intel(R) Visual Fortran Compiler 19.1.2.254 [IA-32]...
2>hello.f90
2>Linking...
2>Embedding manifest...
2>
2>Build log written to "file://D:\c\vs2019\icom\hello\Debug\BuildLog.htm"
2>hello - 0 error(s), 0 warning(s)
========== Rebuild All: 1 succeeded, 1 failed, 0 skipped ==========
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This works in 32 bit mode (in the sense it compiles and does not crash EDI: but not with /CA):
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
#include "ISO_Fortran_binding.h"
#ifdef STEPIMPORTDLL_EXPORTS
#define STEPIMPORTDLL_API extern "C" __declspec(dllexport)
#else
#define STEPIMPORTDLL_API extern "C" __declspec(dllimport)
#endif
extern "C" STEPIMPORTDLL_API int c_testfunction(CFI_cdesc_t* foo_c);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#include "cppdll.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" STEPIMPORTDLL_API int c_testfunction(CFI_cdesc_t* foo_c)
{
int e;
CFI_index_t dim1 = 2;
CFI_index_t dim2 = 4;
CFI_index_t lower_bounds[] = { 1,1 };
CFI_index_t upper_bounds[] = { dim1, dim2 };
int is_established = CFI_establish(foo_c, NULL, CFI_attribute_pointer, CFI_type_int, 0, 2, NULL);
int is_allocated = CFI_allocate(foo_c, lower_bounds, upper_bounds, 0);
e = (is_established == CFI_SUCCESS) && (is_allocated == CFI_SUCCESS) ? 0 : -1; // If allocation failed then e = -1
if (is_allocated == CFI_SUCCESS)
{
int* array = (int*)foo_c->base_addr;
for (CFI_index_t i = 0; i < dim2; ++i)
{
array[i * 2] = i;
array[i * 2 + 1] = i * 10;
}
}
return e;
}
! hello.f90
!
! FUNCTIONS:
! hello - Entry point of console application.
!
!****************************************************************************
!
! PROGRAM: hello
!
! PURPOSE: Entry point for the console application.
!
!****************************************************************************
! Compile: ifort.exe /nologo /CA /stand:f18 /O2 /traceback /module:obj\W64\ /c main.f90 /object:obj\W64\main.obj
! Link: ifort.exe /nologo /exe:bin\W64\F_EXE.exe bin\W64\C_DLL.lib obj\W64\main.obj /link
program hello
use, intrinsic :: iso_c_binding
interface
!subroutine c_testfunction(foo_c) bind(C, name="c_testfunction")
function c_testfunction(foo_c) bind(C, name="c_testfunction")
import
integer(c_int), pointer, intent( out) :: foo_c(:,:)
end function !end subroutine
end interface
integer, allocatable :: bar(:,:)
integer :: iret
call f_testfunction(bar)
write(*,*) bar
write(*,*) iret
contains
subroutine f_testfunction(foo_f)
integer, allocatable, intent( out) :: foo_f(:,:)
integer(c_int), pointer :: foo_c(:,:)
foo_c => null()
!call c_testfunction(foo_c)
iret = c_testfunction(foo_c)
write(*,*)foo_c
allocate(foo_f, source = foo_c)
end subroutine
end program
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
64 bit mode works as well. I do get warnings
>------ Build started: Project: cppdll, Configuration: Debug x64 ------
1>dllmain.cpp
1>D:\c\vs2019\icom\cppdll\ISO_Fortran_binding.h(156,20): warning C4200: nonstandard extension used: zero-sized array in struct/union
1>D:\c\vs2019\icom\cppdll\ISO_Fortran_binding.h(156,20): message : This member will be ignored by a defaulted constructor or copy/move assignment operator
1>D:\c\vs2019\icom\cppdll\dllmain.cpp(39,19): warning C4244: '=': conversion from 'CFI_index_t' to 'int', possible loss of data
1>D:\c\vs2019\icom\cppdll\dllmain.cpp(40,25): warning C4244: '=': conversion from 'CFI_index_t' to 'int', possible loss of data
1> Creating library D:\c\vs2019\icom\x64\Debug\cppdll.lib and object D:\c\vs2019\icom\x64\Debug\cppdll.exp
1>cppdll.vcxproj -> D:\c\vs2019\icom\x64\Debug\cppdll.dll
1>Done building project "cppdll.vcxproj".
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
On a 64 bit build with ?CA I get
forrtl: severe (408): fort: (7): Attempt to use pointer FOO_C when it is not associated with a target
Image PC Routine Line Source
libifcoremdd.dll 00007FFC7C6A746C Unknown Unknown Unknown
hello.exe 00007FF73C3B1369 HELLO_ip_F_TESTFU 46 hello.f90
hello.exe 00007FF73C3B1068 MAIN__ 32 hello.f90
hello.exe 00007FF73C3B1D2E Unknown Unknown Unknown
hello.exe 00007FF73C3B46E9 Unknown Unknown Unknown
hello.exe 00007FF73C3B460E Unknown Unknown Unknown
hello.exe 00007FF73C3B44CE Unknown Unknown Unknown
hello.exe 00007FF73C3B4759 Unknown Unknown Unknown
KERNEL32.DLL 00007FFCF2E26FD4 Unknown Unknown Unknown
ntdll.dll 00007FFCF367CEC1 Unknown Unknown Unknown
which seems the problem as /CA I read as only for 32 bit compiles in an oler intel manual, but I see is in both 32 and 64 bit ifort options. Someone with more knowledge than me needed to explain such.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the confirmation as compiler bug Steve.
I will contact support about it.
@MWind2 good to know it only happens in 64bit
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It happens in 32-bit as well. I must have made a mistake by not changing 32 bit project options.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If the allocation fails in
e = (is_established == CFI_SUCCESS) && (is_allocated == CFI_SUCCESS) ? 0 : -1; // If allocation failed then e = -1
it would seem foo_ c could be null. Is that what /CA should object about when compiled? It seems to crash when the function is called, not after. Just curious.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The allocation in the c++ part is not the problem, as it is never reached. The dv pointer, is "magically" created by the intel fortran core library i think. It is present and allocated, when stepping into the c++ routine (without /CA).
The problem can be reproduced without the cpp part:
subroutine c_testfunction(foo_c) bind(C, name="c_testfunction")
use, intrinsic :: iso_c_binding
integer(c_int), pointer, intent( out) :: foo_c(:,:)
allocate(foo_c(2,4))
foo_c(1,:) = [1,2,3,4]
foo_c(2,:) = [10,20,30,40]
end subroutine
program hello
use, intrinsic :: iso_c_binding
interface
subroutine c_testfunction(foo_c) bind(C, name="c_testfunction")
import
integer(c_int), pointer, intent( out) :: foo_c(:,:)
end subroutine
end interface
integer, allocatable :: bar(:,:)
call f_testfunction(bar)
write(*,*) bar
contains
subroutine f_testfunction(foo_f)
integer, allocatable, intent( out) :: foo_f(:,:)
integer(c_int), pointer :: foo_c(:,:)
foo_c => null()
call c_testfunction(foo_c)
write(*,*)foo_c
allocate(foo_f, source = foo_c)
end subroutine
end program
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It would seem to me that the
foo_c => null()
should be the offence as it would be passed as a null pointer. When I allocate enough or more memory to foo_c before it is passed to c_testfunction, /CA does not object.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It should not matter that the pointer is null before calling the C routine. The dummy argument in the interface is a pointer, so there is no access of the data happening on the Fortran side of the call. The check is in error.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for clearing that up. Is it used correctly in
int is_established = CFI_establish(foo_c, NULL, CFI_attribute_pointer, CFI_type_int, 0, 2, NULL);
where I would think it should not be null.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It would be ok there too. You might want to do a CFI_allocate on it later, for example. A null pointer is a problem only when you're trying to access the data it points to.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Is that because a nullified Fortran pointer is not null like c, but with data structures and memory to "hold a C descriptor of the rank specified by rank".
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Fortran pointers are not like C pointers. In Fortran, they do indeed hold information beyond the data address, and are indirectly accessed when used as ordinary variables. On the C interoperability side, a "C descriptor" is a complex data structure that can describe a scalar, an array, a pointer or an allocatable. The data address is just one aspect of this.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page