- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello all,
I have a c application that runs on both windows and linux. The application includes a number of fortran functions which are called from the c code. On windows (windows 11 24H2), we have been using ifort to compile the fortran code and msvc to compile the c code.
The fortran functions return a struct that contain error information: a return code and a message.
When compiling the same code with ifx instead of ifort, my code fails with the following error:
forrtl: severe (157): Program Exception - access violation
I've been able to narrow it down to a minimal reproduceable error. If I define as a function with a return value (get_struct_byval), the memory address of the struct is different in fortran than it is in the calling c function. However, if I defined a subroutine which returns the struct as an intent(out) argument (get_struct_byref), the memory addresses are the same in both the c and fortran sides. See the attached files.
I can see that the return is different for (get_struct_byval) when comparing the asm generated by ifort and ifx. ifort is correctly setting the address of the struct in RAX (which appears to be to be the expected behavior for the windows x64 ABI) while ifx is not.
Could somebody who's more familiar with the language and ifx confirm whether I'm doing anything incorrect in the attached code? Perhaps there's a compiler flag I'm missing? I'm not seeing anything obviously wrong about the code.
The compiler versions are:
msvc: Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35723 for x64
ifort: Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.9.0 Build 20230302_000000
ifx: Intel(R) Fortran Compiler for applications running on Intel(R) 64, Version 2025.3.2 Build 20260112
all code is compiled with optimization O3 (although the same failure is seen at other optimization levels). Fortran standard 03 is used (again, same error is seen with newer standard versions).
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The windows ABI is described on this page x64 calling conventions. The relevant section:
User-defined types can be returned by value from global functions and static member functions. To return a user-defined type by value in RAX, it must have a length of 1, 2, 4, 8, 16, 32, or 64 bits. ...[snip]... Otherwise, the caller must allocate memory for the return value and pass a pointer to it as the first argument. The remaining arguments are then shifted one argument to the right. The same pointer must be returned by the callee in RAX.
Specifically, in ifort, this is the return from the function:
mov BYTE PTR [19+r14], 0 ;39.9
mov rax, r14 ;40.3
lea rsp, QWORD PTR [112+rbp] ;40.3
pop r14 ;40.3
pop r13 ;40.3
pop rsi ;40.3
pop rbx ;40.3
pop rbp ;40.3
ret ;40.3note that rax is set to r14 before the return (line 2).
While in ifx:
movups %xmm0, 4(%rsi)
.seh_startepilogue
addq $136, %rsp
popq %rbx
popq %rdi
popq %rsi
popq %r14
.seh_endepilogue
retqnote that there's no equivalent mov call.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
apologies, the memory location are a red herring. However the difference in the generated assembly is still relevant I think. The resultant code does return the expected data and run without error when compiled with ifort while it crashes with ifx.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@Igor_V_Intel , this looks like a bug in IFX. May you please quickly review this with Intel Fortran team?
A colleague pointed me to this thread for they are seeing an issue in their code for which they haven't reduced to reproducer but the characteristics are similar to this case by @James_Thunes about a function result that is a derived type with bind(C) attribute.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Glad to hear I'm not the only one @FortranFan. My default reaction to these things is always that I'm making a mistake, but I'm tentatively leaning towards a ifx bug as well. I'd be very happy to hear that it's on my end though.
I do have a workaround (pass the object as an intent(out) argument) but that does require modification to the code. A solution that doesn't require code changes would be preferable.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
For whatever it's worth, the behavior using gfortran and IFORT is as expected.
Intel Fortran team may also consider an added reproducer in this review:
- C main, say file c.c
#include <stdint.h>
#include <stdio.h>
enum { N = 256 };
typedef struct _foo_t {
int32_t i;
char s[N];
} foo_t;
foo_t f();
void main() {
foo_t x;
x = f();
printf("C main: x.i = %d; x.s = %s\n", x.i, x.s);
return;
}- Fortran module, say m.f
module m
use, intrinsic :: iso_c_binding, only : c_int32_t, c_char, c_f_pointer, c_loc, c_null_char
enum, bind(C)
enumerator :: N = 256
end enum
type, bind(C) :: foo_t
integer(c_int32_t) :: i
character(kind=c_char, len=1) :: s(N)
end type
contains
function f() result(r) bind(C, name="f")
! Function result
type(foo_t), target :: r
r%i = 42
block
character(kind=c_char, len=N), pointer :: s
call c_f_pointer( cptr=c_loc(r%s), fptr=s )
s = repeat( c_char_" ", ncopies=N )
s = c_char_"Hello World!" // c_null_char
s => null()
end block
return
end function f
end module- gfortran response with GCC as the companion C processor
C:\Temp>c:\gcc\bin\gcc -c c.c
C:\Temp>c:\gcc\bin\gfortran -c -ffree-form m.f
C:\Temp>c:\gcc\bin\gfortran c.o m.o -o c.exe
C:\Temp>c.exe
C main: x.i = 42; x.s = Hello World!
C:\Temp>- IFX response with Microsoft C/C++ as the companion C processor
C:\Temp>cl /c /W3 /EHsc c.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35721 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
c.c
C:\Temp>ifx /c /free /standard-semantics m.f
Intel(R) Fortran Compiler for applications running on Intel(R) 64, Version 2025.3.2 Build 20260112
Copyright (C) 1985-2026 Intel Corporation. All rights reserved.
C:\Temp>link c.obj m.obj /subsystem:console /out:c.exe
Microsoft (R) Incremental Linker Version 14.50.35721.0
Copyright (C) Microsoft Corporation. All rights reserved.
C:\Temp>c.exe
C main: x.i = 1819043144; x.s = o World!
C:\Temp>Intel team may try this example with the value of enum set to 3. Please look into struct data alignment and bind(C) considerations.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you. I am not sure that this code is standard conforming, e.g.
character(kind=c_char, len=N), pointer :: s
The rule for c_f_pointer is that the Fortran target must be an interoperable data entity. I guess that in this case it is not an interoperable unless N=1. However, I believe there is a bug in the ifx after making this example conform to the standard.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think that you are correct that "only character variables with a length of one (1) are interoperable". That makes sense from the C perspective, as the character array (pointer to an array of characters) needs a spot for the null character at the end. Hence it has a length of 1 when it is created. I'm not very clued up on all of this, but am finding the discussion interesting as it relates to calling/using C libraries from Fortran.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@Igor_V_Intel wrote:Thank you. I am not sure that this code is standard conforming, e.g.
character(kind=c_char, len=N), pointer :: sThe rule for c_f_pointer is that the Fortran target must be an interoperable data entity. I guess that in this case it is not an interoperable unless N=1. However, I believe there is a bug in the ifx after making this example conform to the standard.
For the sake of the issue with IFX on hand, please ignore the above distraction. Please consider the following variant with IFX review.
module m
use, intrinsic :: iso_c_binding, only : c_int32_t, c_char, c_f_pointer, c_loc, c_null_char
enum, bind(C)
enumerator :: N = 256
end enum
type, bind(C) :: foo_t
integer(c_int32_t) :: i
character(kind=c_char, len=1) :: s(N)
end type
contains
function f() result(r) bind(C, name="f")
! Function result
type(foo_t), target :: r
! Local entities
integer :: i
character(kind=c_char, len=*), parameter :: s = c_char_"Hello World!" // c_null_char
r%i = 42
r%s = repeat( c_char_" ", ncopies=N )
do i = 1, len(s)
r%s(i) = s(i:i)
end do
return
end function f
end module
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, the above is a more concise representation of the problem I believe. Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you, @FortranFan . I have escalated it to be fixed (CMPLRLLVM-74139).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
thanks @Igor_V_Intel. Is the above bug (CMPLRLLVM-74139) publicly available so I can track its progress?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi @james-thunes . Unfortunately not. It is more for your reference if you contact Intel support to ask for an update. I will notify you and the community here once the bug is fixed.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Not a problem. That'll be sufficient for my purposes.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The language has a carve-out for passing character values with length greater than 1 to character array dummy arguments.
"Fortran’s rules of sequence association (15.5.2.12) permit a character scalar actual argument to correspond to
a dummy argument array. This makes it possible to argument associate a Fortran character string with a C
string."
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks @Steve_Lionel good to know. Dealing with character arrays in c is always a minefield. Glad that there's some guidance on how to do so in the fortran standard.
This is, however, perhaps a little orthogonal to my actual issue. The use of a string in the object I'm returning from the function was in retrospect a bad choice. It was done since it was representative of the simplest use-case that was failing in my ported code, but the same result can be seen with other objects as well. Of note is that the opposite case, passing the same data from c to fortran, does not exhibit the same behavior.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page