corrupt value when passing integer from fortran to void * in C function

corrupt value when passing integer from fortran to void * in C function

SYSTEM INFO:

ProductName:    Mac OS X
ProductVersion:    10.8.5
BuildVersion:    12F45

Intel(R) Fortran Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 14.0 Build 20131010
Copyright (C) 1985-2013 Intel Corporation.  All rights reserved.

When I compile the Fortran program:

module test
 INTERFACE
     FUNCTION h5dwrite_f_c2(buf)
       USE, INTRINSIC :: ISO_C_BINDING
       INTEGER(C_INT) :: h5dwrite_f_c2
       TYPE(C_PTR), VALUE :: buf
     END FUNCTION h5dwrite_f_c2
  END INTERFACE

 INTERFACE
     FUNCTION h5dwrite_f_c3(buf) BIND(C,NAME="h5dwrite_f_c3")
       USE, INTRINSIC :: ISO_C_BINDING
       INTEGER(C_INT) :: h5dwrite_f_c3
       TYPE(C_PTR), VALUE :: buf
     END FUNCTION h5dwrite_f_c3
  END INTERFACE
end module test

PROGRAM fortranlibtest
  USE test
  USE, INTRINSIC :: ISO_C_BINDING
  IMPLICIT NONE
    INTEGER(C_INT) :: hdferr
    TYPE(C_PTR) :: f_ptr
    integer(C_INT), target :: buf2

    buf2 = 200
    f_ptr = C_LOC(buf2)

    hdferr = h5dwrite_f_c3(f_ptr)
    hdferr = h5dwrite_f_c2(f_ptr)

END PROGRAM fortranlibtest

AND THE C PROGRAM:

#include <stdio.h>

#define H5_FC_FUNC_(name,NAME) name ## _

#define nh5dwrite_f_c2             H5_FC_FUNC_(h5dwrite_f_c2, H5DWRITE_F_C2)
int nh5dwrite_f_c2(void *buf);

int
nh5dwrite_f_c2 (void *buf)
{
  int *name;
  name = (int*)buf;
  printf(" Buffer In nh5dwrite_f_c2 = %d \n", *name);
  return 0;
}

int
h5dwrite_f_c3 (void *buf)
{
  int *name;

  name = (int*)buf;
  printf(" Buffer In h5dwrite_f_c3 = %d \n", *name);
  return 0;
}

AND THE MAKEFILE:

# INTEL COMPILER
CC  = icc
F90 = ifort

F90FLAGS = -g
CFLAGS = -g

OBJ = ccode.o

OBJF90 = fcode.o

all: ex12

ex12: $(OBJ) $(OBJF90)
        $(F90) $(CFLAGS) $(LDFLAGS) $(OBJ) $(OBJF90) -o $@ $(LIB)

.SUFFIXES: .o .f90

.f90.o:
        $(F90) $(F90FLAGS) -c $< -o $@ $(LIB)

.SUFFIXES: .o .c

.c.o:
        $(CC)  $(CFLAGS) $(LDFLAGS)  -c  $< -o $@ $(LIB)

clean:
        rm -f *.o *.mod ex12

spotless:
        rm -f *.o *.mod ex12 *~

I GET AS OUPUT:

 Buffer In h5dwrite_f_c3 = 200
 Buffer In nh5dwrite_f_c2 = 1400015680

I.E. the second value pointed to by the pointer in C is wrong. It works with gnu compiler and in linux with

Intel(R) Fortran Compiler XE for applications running on IA-32, Version 13.1.3.192 Build 20130607
Copyright (C) 1985-2013 Intel Corporation.  All rights reserved.

Thanks,

Scot

 

I've also attached the files.

 

 

 

 

 

 

 

 

AllegatoDimensione
Download ex12.tar4.5 KB
16 post / 0 nuovi
Ultimo contenuto
Per informazioni complete sulle ottimizzazioni del compilatore, consultare l'Avviso sull'ottimizzazione
Ritratto di Steve Lionel (Intel)
Steve

I tried both the options in the thread you referenced, -standard-semantics  -assume std_value, and neither fixes the problem. Is this a bug with the compiler or is the code not standard compliant? I was not aware of the VALUE attribute having a different meaning depending on if BIND(C) is used. I'm assuming you are referring to NOTE 12.22 in the F2003 standard, but I don't see the association with BIND(C), where in the standard is that? Thanks, I hope this can be resolved because the HDF5 Fortran library depends on this working.

 

Ritratto di Steve Lionel (Intel)

It's a compiler bug - I was not suggesting that your case would be solved with an option.

In F2008, the relevant text is 15.3.7 (Interoperability of procedures and procedure interfaces), paragraph 2, clauses 4 and 5. It's not inherently obvious until you study the words and see what the difference between clauses 4 and 5 is: I quote them here for reference:

12 (4) any dummy argument with the VALUE attribute is interoperable with the corresponding formal
13 parameter of the prototype,

14 (5) any dummy argument without the VALUE attribute corresponds to a formal parameter of the pro-
15 totype that is of a pointer type, and the dummy argument is interoperable with an entity of the
16 referenced type (ISO/IEC 9899:1999, 6.2.5, 7.17, and 7.18.1) of the formal parameter,

Steve
Ritratto di Steve Lionel (Intel)

I expect this to be fixed in Update 2, due late January or early February.

Steve

Thanks for the update Steve, we look forward to the update.

Update 2 fixed the problem, thanks.

Argh,

This same error is back in 15.0, repeat the above steps to see. This is very frustrating as we now have to field HDF5 users complaints that are using 14.0.0 and 14.0.1 (was fixed in 14.0.2) and now again for 15.0.0 and 15.0.1.

Can you please fix this error again and add some regression tests (You are more then welcome to use HDF5 as your regression test :) ).

Thanks.

Keywords for search engines to find this thread: HDF5, Fortran, Intel 14.0.1, Intel 14.0.0, Intel 14.0.2, HDF5 1.8.13, HDF5 1.8.14, Intel 15.0.0, Intel 15.0.1, Fails, crashes, segfaults, wrong value, --enable-fortran2003, Fortran 2003, make check, fortranlib_test_F03, fortranlib_test_1_8, fortranlib_test

 

Ritratto di Steve Lionel (Intel)

I'm not sure what happened here - we had a regression test but it wasn't exactly like the one here which is why it wasn't noticed. We'll get this fixed and use this code as the test.

Steve
Ritratto di Steve Lionel (Intel)

I take it back - this is not a compiler bug, it's a coding error in the application. As I explained earlier, we did have a bug in how we treated the Fortran standard VALUE attrribute when applied to a procedure that did not have BIND(C). In version 14 we kept the old behavior but added -assume std_value to get the new behavior. This was also enabled with -standard-semantics.

In version 15, std_value is the default, as documented. This causes the call to hdwrite_f_c2 to pass the address of a copy of the argument, as specified by the standard. You can get the old behavior with -assume nostd_value. Better is to use BIND(C) if that's what you want.

Steve
Ritratto di Repeat Offender

I can't see how passing an argument with the VALUE attribute by value can be a bug. It seems to me that everyone did this, but that there was a problem with arguments that had both the VALUE and OPTIONAL arguments. The approach of changing all VALUE arguments to reference to copy was only one of several possibilities, as far as I can see. Why isn't passing non-OPTIONAL VALUE arguments by value and OPTIONAL, VALUE arguments by reference to copy acceptable? This way old code that counted on true VALUE semantics would not have been broken, and VALUE, OPTIONAL would have worked. The compiler always has to know which choice it has to make because either one of VALUE or OPTIONAL triggers explicit interface requirements.

 

This is my understanding: the code itself is standard compliant, but the standard says that if you don't use BIND(C)  then there is no  guarantee of interoperability with C. It appears that the Intel compiler (and only the Intel compiler BTW) is forcing you to use BIND(C) in order to be interoperable with C. Yea, that is going to break a lot of code where people were taking care of the interoperability themselves. Plus it is a pain to dectect automatically this new defualt behavior (unless you use compiler version numbers, yuck) during configure so that you can add this intel specific flag... sigh.

Quote:

Michael B. wrote:

This is my understanding: the code itself is standard compliant, but the standard says that if you don't use BIND(C)  then there is no  guarantee of interoperability with C. It appears that the Intel compiler (and only the Intel compiler BTW) is forcing you to use BIND(C) in order to be interoperable with C. Yea, that is going to break a lot of code where people were taking care of the interoperability themselves. Plus it is a pain to dectect automatically this new defualt behavior (unless you use compiler version numbers, yuck) during configure so that you can add this intel specific flag... sigh.

If a Fortran program calls a procedure defined by C without the BIND(C) attribute on the procedure interface, the program is non-conforming.  No guarantee of interoperability is a consequence of that non-conformance.

VALUE and BIND(C) are related F2003 features, typically introduced to compilers at the same time.  Consequently it would be a bit bizarre to write code that only used one attribute when both were needed.

There are a number of compilers where the wheels will fall off in some way if you don't use BIND(C) on the interface of a procedure defined by C that is otherwise interoperable.

Prior to F2003, when people were taking care of it themselves, this was all compiler specific.  !DEC$ ATTRIBUTES VALUE and all that jazz for ifort.  That stuff hasn't changed, modulo bugs.

I agree with RO's queries/comments about where there really was a need for the change for the non-BIND(C), standard VALUE attribute case though.  The original implementation seemed more consistent with my assumed intent of the attribute.  ("pass an address of a copy of the argument" can't be a standard specification - "pass" and "address" aren't Fortran terms in that context (them's C words!!) - that's a description of a (valid) implementation choice.)

Ritratto di Steve Lionel (Intel)

First, let me point out that the issue being discussed here is NOT the issue of the original complaint from January 2014. That one dealt with how the compiler treated a derived type being passed to a BIND(C) routine where VALUE was specified. So it is not a case of the bug returning, but that the behavior of the call to the routine without BIND(C) changed.

In the case of a call to a routine without BIND(C) and where the dummy argument has VALUE specified, the standard says:

"A present dummy argument with the VALUE attribute becomes argument associated with a definable anonymous data object whose initial value is the value of the actual argument." (12.5.2.3, paragraph 4)

While it is true that the standard doesn't talk about "pass a copy by reference", that's how we interpret these words. I agree that any assumptions one makes about how the argument is actually passed are invalid - a correct Fortran program would not be able to tell. Theoretically, one could pass the actual argument by value and make a copy in the called routine, but that breaks down for larger actual arguments, so the implementation we have chosen is the only practical one. The compiler's old behavior, the one you get with -assume nostd_value, is not supportable for all standard-conforming code, which is why we changed it.

It is also true that "all bets are off" when calling a non-Fortran routine and not using BIND(C). In such cases, it is implementation-dependent how things are actually passed.  So my comment that the original posted code being incorrect is valid - it may have matched the undocumented behavior of ifort in older versions, but it was not supported by the standard. We fixed our bug and made VALUE do the right thing for non-BIND(C) routines.

Steve
Ritratto di Repeat Offender

I have to admit that Quote #14 makes no sense to me whatsoever. The third paragraph, quoting the standard, seems to me to be identical to how C passes everything, unless passing by reference leaked from C++ into some edition of the C standard. C passes everything by value, and the ABI dictates whether the anonymous data object resides in a register, on the stack, or in some region of memory pointed to by a register or an address on the stack. So I don't see how this forces Fortran to pass all arguments with the VALUE attribute by reference to a copy since C isn't forced to do so.

The fourth paragraph begs for a Fortran program that can distinguish between true value and reference to a copy, ergo:

! Has the procedure whose interface we want to test
module M1
   use ISO_C_binding
   implicit none
   contains
      subroutine sub(x)
         type(C_PTR), value :: x
         ! The real subroutine does something with x here :)
      end subroutine sub
end module M1

! Has the test procedure
module M2
   use ISO_C_BINDING
   implicit none
   contains
      subroutine test(x) bind(C,name='TEST')
         type(C_PTR), value :: x
         if(C_ASSOCIATED(x)) then
            write(*,*) 'Argument x was passed by reference to a copy.'
         else
            write(*,*) 'Argument x was passed by value.'
         end if
      end subroutine test
end module M2

module M3
   use M1
   implicit none
   interface
      subroutine test(x)
         use ISO_C_BINDING
         implicit none
         type(C_PTR), value :: x
      end subroutine test
   end interface
end module M3

program p
   use M1
   use M3
   implicit none
   procedure(sub), pointer :: fptr
   ! Check that interfaces match
   fptr => test
   call test(C_NULL_PTR)
end program p

This tells us whether /assume:std_value or /assume:nostd_value was in force. It figures this out the same way a C or assembler program would.

The fourth paragraph also hints at Fortran programs where /assume:nostd_value is invalid. Since there are those of us who gots to know. can you make our day by providing an example?

As for the fifth paragraph, what is the problem with invoking a C function using the Fortran specification? This is what was always done before C interoperability. The corresponding C function has to be very carefully written to take into account the way the specific Fortran compiler will implement the interface, but that was the old way of doing things and I never heard of either the C or Fortran side of this being non-standard.

 

Ritratto di Steve Lionel (Intel)

I am out of the office for the next week, so can't comment in too much detail, but maybe you should reread your last paragraph.

Before the C interoperability features in F2003, it was possible to mix C and Fortran but only if you had detailed knowledge about how your particular Fortran did things. Fortran implementations added nonstandard directives and C code sprouted voluminous conditional code to accommodate such variables as case of name, where underscores were, where string lengths got passed and more that changed from implementation to implementation (and platform to platform.)

With the advent of F2003, it was now possible to write a single Fortran source and a single C source that played well together without any directives that was portable.

The Fortran standard doesn't really talk about how things are passed. For interoperable interfaces, it talks about Fortran arguments being compatible with C arguments (parameters) declared in a particular way (see post 4.)

We aren't talking C anymore, though. The discussion as of late relates to calls where the called procedure is not declared with BIND(C), hence it is presumed to be Fortran. This topic was raised today in comp.lang.fortran and Richard Maine, former Fortran standard editor, had a good response:

No, the Fortran standard does not guarantee that *ANYTHING* will
interoperate with C code if you don't use BIND(C). There are common
practices that usually worked, albeit with various tweaks in some cases,
prior to the introduction of BIND(C). But the Fortran standard never
guaranteed them to work, and it still doesn't have such a guarantee.

Having something that was actually specified in the standard was sort of
the point of BIND(C).

I'm home now and don't have access to our database that would provide the example you are looking for. When I return I will look for it.

Steve

Accedere per lasciare un commento.